打包完成后的应用程序文件(exe文件,无需配置python环境)提取网址:

百度网盘:

链接: https://pan.baidu.com/s/1AVKogVxuipChTISw08cZVQ    提取码: er5w 

蓝奏云:

链接:https://wwqc.lanzouu.com/i0KM737xtisj       密码:hp8a

夸克网盘:

链接:https://pan.quark.cn/s/f6292c3c184c           提取码:ZKmu

C++源代码:

//吝旭涵原创
#include<bits/stdc++.h>
#include<windows.h>
using namespace std;
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
#define KEY_DOWN(VK_NONAME) ((GetAsyncKeyState(VK_NONAME) & 0x8000) ? 1:0)
POINT p;
HWND h = GetForegroundWindow();
int gamekunnan;
//全局变量
int gameplayer=1;
int qi_p[18][18];//棋盘、
int return_map[4][18][18];
int gamerule = 3; //游戏状态:1为失败,2为胜利,3为正在进行
int a, b; //ai对手下棋的x和y坐标
int fx[4][2] = { {1, 1}, {1, 0}, {0, 1}, {1, -1}};
int gamemode;//下棋先后手
int output=3;//剩余悔棋次数
int x, y;
int gamepalce;
int gamestartx,gamestarty;
int csh() { //初始化棋盘
	for (int i = 0; i < 18; i++) {
		for (int j = 0; j < 18; j++) {
			qi_p[i][j] = 0; //初始化
		}
	}
	return 0;
}
//清空缓存
int white_map(){
	for(int i=0;i<4;i++){
		for(int j=0;j<18;j++){
			for(int k=0;k<18;k++){
				return_map[i][j][k]=0;
			}
		}
	}
}
//将棋盘数据写入缓存
int move_the_map(){
	for(int i=1;i<4;i++){
		for(int j=0;j<18;j++){
			for(int k=0;k<18;k++){
				return_map[i-1][j][k]=return_map[i][j][k];
			}
		}
	}
	for(int i=0;i<18;i++){
		for(int j=0;j<18;j++){
			return_map[3][i][j]=qi_p[i][j];
		}
	}	
}
//悔棋后迁移棋盘数据
int if_move_the_map(){
	for(int i=0;i<18;i++){
		for(int j=0;j<18;j++){
			qi_p[i][j]=return_map[2][i][j];
		}
	}
	for(int i=3;i>=1;i--){
		for(int j=0;j<18;j++){
			for(int k=0;k<18;k++){
				return_map[i][j][k]=return_map[i-1][j][k];
			}
		}
	}
}
//转换坐标;四舍五入
int fouroutfivein() {
	float x1 = (p.y - 24) / 39;
	float y1 = (p.x - 24) / 39;
	int x2 = int(x1);
	int y2 = int(y1);
	if (x1 - x2 >= 0.5) {
		x = x2 + 1;
	} else {
		x = x2;
	}
	if (y1 - y2 >= 0.5) {
		y = y2 + 1;
	} else {
		y = y2;
	}
	return 0;
}
int getmouemmouve() {
	GetCursorPos(&p);
	ScreenToClient(h, &p);
	fouroutfivein();
	return 0;
}
void mouseleftkeydown() {
	HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
	DWORD mode;
	GetConsoleMode(hStdin, &mode);
	mode &= ~ENABLE_QUICK_EDIT_MODE;
	SetConsoleMode(hStdin, mode);
	while (1) {
		if (KEY_DOWN(VK_LBUTTON)) {
			getmouemmouve();
			return;
		}
		Sleep(20);
	}
 
}
 
void clearScreen() {
	COORD coordScreen = { 0, 0 };
	SetConsoleCursorPosition(hConsole, coordScreen);
}
// 辅助函数,用于检查指定方向是否有连续n个棋子
bool checkDirection(int x, int y, int dx, int dy, int player, int n) {
	int count = 1;
	for (int i = 1; i < n; ++i) {
		int nx = x + i * dx;
		int ny = y + i * dy;
		if (nx >= 0 && nx < 18 && ny >= 0 && ny < 18 && qi_p[nx][ny] == player) {
			++count;
		} else {
			break;
		}
	}
	for (int i = 1; i < n; ++i) {
		int nx = x - i * dx;
		int ny = y - i * dy;
		if (nx >= 0 && nx < 18 && ny >= 0 && ny < 18 && qi_p[nx][ny] == player) {
			++count;
		} else {
			break;
		}
	}
	return count >= n;
}
void timesleep(int microseconds) {
	LARGE_INTEGER frequency;
	LARGE_INTEGER start, current;
	double elapsedMicroseconds;
	QueryPerformanceFrequency(&frequency);
	double waitTicks = static_cast<double>(microseconds) * frequency.QuadPart / 1e6;
	QueryPerformanceCounter(&start);
	do {
		QueryPerformanceCounter(&current);
		elapsedMicroseconds = static_cast<double>(current.QuadPart - start.QuadPart) * 1e6 / frequency.QuadPart;
	} while (elapsedMicroseconds < microseconds);
}
void Color(int colorpaint) {
	if (colorpaint == 0) {
		SetConsoleTextAttribute(hConsole, BACKGROUND_RED | BACKGROUND_GREEN | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
	}
	if (colorpaint == 1) {
		SetConsoleTextAttribute(hConsole, BACKGROUND_RED | BACKGROUND_GREEN );
	}
	if (colorpaint == 2) {
		SetConsoleTextAttribute(hConsole, BACKGROUND_RED | BACKGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE);	
	}
	if (colorpaint == 3){
		SetConsoleTextAttribute(hConsole, BACKGROUND_GREEN | BACKGROUND_GREEN | FOREGROUND_BLUE | BACKGROUND_INTENSITY);
	}
}
int printj() {
	cout << "  ║   │   │   │   │   │   │   │   │   │   │   │   │   │   │   │   │   │   │   ║" << endl;
	return 0;
}
int screen() {
	cout << "      1   2   3   4   5   6   7   8   9   10  11  12  13  14  15  16  17  18 " << endl;
	cout << "  ╔═══╤═══╤═══╤═══╤═══╤═══╤═══╤═══╤═══╤═══╤═══╤═══╤═══╤═══╤═══╤═══╤═══╤═══╤═══╗" << endl;
	printj();
	for (int i = 0; i < 18; i++) {
		if (i <= 8) {
			cout << " ";
		}
		cout << i + 1;
		cout << "║─";
		for (int j = 0; j < 18; j++) {
			if (qi_p[i][j] == 0) {
				cout << "──┼─";
			}
 
			if (qi_p[i][j] == 1) {
				cout << "──";
				Color(1);
				cout << "●";
 
			}
			if (qi_p[i][j] == 2) {
				cout << "──";
				Color(0);
				cout << "●";
				Color(1);
			}
		}
		cout << "──╢" << endl;
		printj();
	}
	cout << "  ╚═══╧═══╧═══╧═══╧═══╧═══╧═══╧═══╧═══╧═══╧═══╧═══╧═══╧═══╧═══╧═══╧═══╧═══╧═══╝" << endl;
 
	return 0;
}
int arnd(int x, int y) {
	int cnt = 0;
	for (int i = x - 1; i <= x + 1; i++) {
		if (i >= 0 && i < 18) {
			for (int j = y - 1; j <= y + 1; j++) {
				if (j >= 0 && j < 18) {
					if (qi_p[i][j] > 0) cnt++;
				}
			}
		}
	}
	return cnt;
}
void get_val(int x, int y, int &val) {
	val = 0;
	for (int i = 0; i < 18; i++) {
		for (int j = 0; j < 18; j++) {
			for (int Fx = 0; Fx < 4; Fx++) {
				int xx = i, yy = j, tmp = 0, tk = 0;
				for (int k = 1; k <= 5; k++) {
					if (xx < 0 || xx >= 18 || yy < 0 || yy >= 18) {
						tmp = 0;
						break;
					}
					if (qi_p[xx][yy] == (x ^ 3)) {
						tmp = 0;
						break;
					}
					if (qi_p[xx][yy] == x) tmp++, tk += (1 << (k - 1));
					xx += fx[Fx][0], yy += fx[Fx][1];
				}
				switch (tmp) {
					case 5:
						val += 800000000;
						break;
					case 4:
						val += 1000 + 350 * y;
						break;
					case 3:
						val += (tk == 14) ? (300 + 600 * y) : (300 + 200 * y);
						break;
					case 2:
						val += 3 + 2 * y;
						break;
					case 1:
						val += 1 + y;
						break;
				}
			}
		}
	}
}
bool check_win(int player) {
	for (int i = 0; i < 18; ++i) {
		for (int j = 0; j < 18; ++j) {
			if (qi_p[i][j] == player) {
				if (checkDirection(i, j, 0, 1, player, 5)) return true;
				if (checkDirection(i, j, 1, 0, player, 5)) return true;
				if (checkDirection(i, j, 1, 1, player, 5)) return true;
				if (checkDirection(i, j, 1, -1, player, 5)) return true;
			}
		}
	}
	return false;
}
int evaluate(int ai_player) {
	int human_player = (ai_player == 1) ? 2 : 1;
	if (check_win(ai_player)) return INT_MAX;
	if (check_win(human_player)) return INT_MIN;
	int ai_score, human_score;
	get_val(ai_player, 10, ai_score);
	get_val(human_player, 80, human_score);
	return ai_score - human_score;
}
int minimax(int depth, int alpha, int beta, bool maximizingPlayer, int ai_player) {
	int human_player = (ai_player == 1) ? 2 : 1;
	int game_result = evaluate(ai_player);
	if (game_result == INT_MAX) return INT_MAX - depth;
	if (game_result == INT_MIN) return INT_MIN + depth;
	if (depth == 0) return game_result;
 
	vector<pair<int, int>> moves;
	for (int i = 0; i < 18; ++i) {
		for (int j = 0; j < 18; ++j) {
			if (qi_p[i][j] == 0 && arnd(i, j) > 0) {
				moves.push_back({i, j});
			}
		}
	}
	sort(moves.begin(), moves.end(), [](const pair<int, int>& a, const pair<int, int>& b) {
		return arnd(a.first, a.second) > arnd(b.first, b.second);
	});
 
	if (maximizingPlayer) {
		int maxEval = INT_MIN;
		for (auto& move : moves) {
			qi_p[move.first][move.second] = ai_player;
			int eval = minimax(depth - 1, alpha, beta, false, ai_player);
			qi_p[move.first][move.second] = 0;
			maxEval = max(maxEval, eval);
			alpha = max(alpha, eval);
			if (beta <= alpha) break;
		}
		return maxEval;
	} else {
		int minEval = INT_MAX;
		for (auto& move : moves) {
			qi_p[move.first][move.second] = human_player;
			int eval = minimax(depth - 1, alpha, beta, true, ai_player);
			qi_p[move.first][move.second] = 0;
			minEval = min(minEval, eval);
			beta = min(beta, eval);
			if (beta <= alpha) break;
		}
		return minEval;
	}
}
int AI_k(int ai) {
	int bestScore = INT_MIN;
	int ai_player = (gamemode == 0) ? 2 : 1;
	vector<pair<int, int>> bestMoves;
	vector<pair<int, int>> moves;
	for (int i = 0; i < 18; ++i) {
		for (int j = 0; j < 18; ++j) {
			if (qi_p[i][j] == 0 && arnd(i, j) > 0) {
				moves.push_back({i, j});
			}
		}
	}
	if (moves.empty()) {
		for (int i = 0; i < 18; ++i) {
			for (int j = 0; j < 18; ++j) {
				if (qi_p[i][j] == 0) {
					moves.push_back({i, j});
				}
			}
		}
	}
	sort(moves.begin(), moves.end(), [](const pair<int, int>& a, const pair<int, int>& b) {
		return arnd(a.first, a.second) > arnd(b.first, b.second);
	});
 
	int depth = ai;
	for (auto& move : moves) {
		qi_p[move.first][move.second] = ai_player;
		int currentScore = minimax(depth - 1, INT_MIN, INT_MAX, false, ai_player);
		qi_p[move.first][move.second] = 0;
 
		if (currentScore > bestScore) {
			bestScore = currentScore;
			bestMoves.clear();
			bestMoves.push_back(move);
		} else if (currentScore == bestScore) {
			bestMoves.push_back(move);
		}
	}
 
	if (!bestMoves.empty()) {
		int bestArnd = -1;
		pair<int, int> bestMove;
		for (auto& move : bestMoves) {
			int currentArnd = arnd(move.first, move.second);
			if (currentArnd > bestArnd) {
				bestArnd = currentArnd;
				bestMove = move;
			}
		}
		a = bestMove.first + 1;
		b = bestMove.second + 1;
	} else if (!moves.empty()) {
		a = moves[0].first + 1;
		b = moves[0].second + 1;
	} else {
		a = 9, b = 9;
	}
	return 0;
}
int AI(){
	AI_k(gamekunnan);
	return 0; 
}
int win_or_lose() {
	int player = (gamemode == 0) ? 1 : 2;
	int opponent = (player == 1) ? 2 : 1;
	for (int i = 0; i < 18; ++i) {
		for (int j = 0; j < 18; ++j) {
			if (qi_p[i][j] == player) {
				if (checkDirection(i, j, 0, 1, player, 5)) return 2;
				if (checkDirection(i, j, 1, 0, player, 5)) return 2;
				if (checkDirection(i, j, 1, 1, player, 5)) return 2;
				if (checkDirection(i, j, 1, -1, player, 5)) return 2;
			}
		}
	}
	bool fullBoard = true;
	for (int i = 0; i < 18; ++i) {
		for (int j = 0; j < 18; ++j) {
			if (qi_p[i][j] == 0) {
				fullBoard = false;
				break;
			}
		}
		if (!fullBoard) break;
	}
	if (fullBoard) return 0;
	return 3;
}
int return_moseleftkeydown(){
    HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
	DWORD mode;
	GetConsoleMode(hStdin, &mode);
	mode &= ~ENABLE_QUICK_EDIT_MODE;
	SetConsoleMode(hStdin, mode);
	while (1) {
		if (KEY_DOWN(VK_LBUTTON)) {
			GetCursorPos(&p);
			ScreenToClient(h, &p);
			gamestartx=p.x;
			gamestarty=p.y;
			//cout<<gamestartx<<"   "<<gamestarty<<" :: ";
			if(gamestartx>=10 and gamestartx<=130 and gamestarty>=830 and gamestarty<=870){
				return 1;
			}else{
				return 0;
			}
		}
		Sleep(20);
	}
}
void print_return(){
	cout<<"剩余悔棋次数:"<<output<<"次。          "<<endl;
	cout<<"╔═══════════╗"<<endl;
	cout<<"║   悔  棋  ║"<<endl;;
	cout<<"╚═══════════╝"<<endl;
}
void returnmap(){
	output-=1;
	if_move_the_map();
	clearScreen();
	screen();
	print_return();
    Sleep(300);
}
int Game() {
	csh();
	while (true) {
		if (gamemode == 0) {
			clearScreen();
			screen();
			print_return();
			mouseleftkeydown();
			while (1) {
				if (x > 18 or y > 18 or x <= 0 or y <= 0) {
					if(return_moseleftkeydown() and output>0){
						returnmap();
					}else{
						clearScreen();
						screen();
						print_return();
					}
					
					mouseleftkeydown();
				} else if (qi_p[x - 1][y - 1] != 0) {
					clearScreen();
					screen();
					print_return();
					mouseleftkeydown();
				} else {
					break;
				}
			}
			if (gamemode == 0) {
				qi_p[x - 1][y - 1] = 1;
			}
			if (gamemode == 1) {
				qi_p[x - 1][y - 1] = 2;
			}
			if (win_or_lose() == 2) {
				gamerule = 2;
				return 0;
			}
			clearScreen();
			screen();
			Color(2);
			cout<<"ai正在思考中,时间可能较长"<<endl;
			cout<<"                                                   "<<endl;
			cout<<"                                                   "<<endl;
			cout<<"                                                   "<<endl;
			Color(1);
			AI();
			int ai_player = (gamemode == 0) ? 2 : 1;
			if (gamemode == 0) {
				qi_p[a - 1][b - 1] = 2;
			}
			if (gamemode == 1) {
				qi_p[a - 1][b - 1] = 1;
			}
			if (check_win(ai_player)) {  // 修改此处判断条件
				gamerule = 1;
				return 0;
			}
			move_the_map();
		}
		if (gamemode == 1) {
			clearScreen();
			screen();
			Color(2);
			cout<<"ai正在思考中,时间可能较长"<<endl;
			cout<<"                                                   "<<endl;
			cout<<"                                                   "<<endl;
			cout<<"                                                   "<<endl;
			Color(1);
			if(gameplayer!=1){
				AI();
			}else{
				gameplayer=2;
				a=9;
				b=9;
			}
			int ai_player = (gamemode == 0) ? 2 : 1;
			if (gamemode == 0) {
				qi_p[a - 1][b - 1] = 2;
			}
			if (gamemode == 1) {
				qi_p[a - 1][b - 1] = 1;
			}
			if (check_win(ai_player)) {  // 修改此处判断条件
				gamerule = 1;
				return 0;
			}
			move_the_map();
			clearScreen();
			screen();
			//cout<<"                                   "<<endl;
			print_return();
			mouseleftkeydown();
			while (1) {
			    if (x > 18 or y > 18 or x <= 0 or y <= 0) {
					if(return_moseleftkeydown() and output>0){
						returnmap();
					}else{
						clearScreen();
						screen();
						print_return();
					}								
					mouseleftkeydown();
				} else if (qi_p[x - 1][y - 1] != 0) {
					clearScreen();
					screen();
				    print_return();
					mouseleftkeydown();
				} else {
					break;
				}
			}
			if (gamemode == 0) {
				qi_p[x - 1][y - 1] = 1;
			}
			if (gamemode == 1) {
				qi_p[x - 1][y - 1] = 2;
			}
			if (win_or_lose() == 2) {
				gamerule = 2;
				return 0;
			}
 
		}
	}
}
void print_win_or_lose() {
	system("mode con cols=80 lines=45");
	if (gamerule == 1) {
		clearScreen();
		screen();
		SetConsoleTextAttribute(hConsole, BACKGROUND_RED | BACKGROUND_GREEN | FOREGROUND_RED );
		cout << "你输了                                         " << endl;
		Color(1);
	} else if (gamerule == 2) {
		clearScreen();
		screen();
		SetConsoleTextAttribute(hConsole, BACKGROUND_RED | BACKGROUND_GREEN | FOREGROUND_RED );
		cout << "你赢了                                        " << endl;;
		Color(1);
	}
}
int intro_moseleftkeydown(){
    HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
	DWORD mode;
	GetConsoleMode(hStdin, &mode);
	mode &= ~ENABLE_QUICK_EDIT_MODE;
	SetConsoleMode(hStdin, mode);
	while (1) {
		if (KEY_DOWN(VK_LBUTTON)) {
			GetCursorPos(&p);
			ScreenToClient(h, &p);
			gamestartx=p.x;
			gamestarty=p.y;
			if(gamestartx>=540 and gamestartx<=680 and gamestarty>=430 and gamestarty<=470){
				return 1;
			}
		}
		Sleep(20);
	}
}
int intro() { //游戏开始界面
	cout << "╔═══════════════════════════════════════════════════════════════════╗" << endl;
	cout << "║                                                                   ║" << endl;
	cout << "║     ***欢迎运行五子棋游戏!***                                    ║" << endl;
	cout << "║                                                                   ║" << endl;
	cout << "║                                                                   ║" << endl;
	cout << "║                                                                   ║" << endl;
	cout << "║   【游戏规则如下:】                                              ║" << endl;
	cout << "║                                                                   ║" << endl;
	cout << "║   执黑棋者为先手                                                  ║" << endl;
	cout << "║                                                                   ║" << endl;
	cout << "║   在这个游戏里会有一个 18*18 的棋盘                               ║" << endl;
	cout << "║                                                                   ║" << endl;
	cout << "║   游戏目标是棋子在任意一个方向上连成5个,最先成功者胜利           ║" << endl;
	cout << "║                                                                   ║" << endl;
	cout << "║   每次点击要下棋的位置(点击位置必须在隔线交叉点上)              ║" << endl;
	cout << "║                                                                   ║" << endl;
	cout << "║   你将和ai进行对战                                                ║" << endl;
	cout << "║                                                                   ║" << endl;
	cout << "║                                             ";
	SetConsoleTextAttribute(hConsole,  BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_INTENSITY);
	cout << "【原创】吝旭涵";
	SetConsoleTextAttribute(hConsole, FOREGROUND_RED | BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_INTENSITY);
	cout << "        ║" << endl;
	cout << "║   ";
	Color(3);
	cout <<"【注意:】难度越高,AI下棋速度越慢!";
	SetConsoleTextAttribute(hConsole, FOREGROUND_RED | BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_INTENSITY);
	cout <<"                            ║" << endl;
	cout << "╚═══════════════════════════════════════════════════════════════════╝" << endl;
	cout << "                                                     ╔═════════════╗" << endl;
	cout << "                                                     ║ 开 始 游 戏 ║" << endl;
	cout << "                                                     ╚═════════════╝" << endl;
	if(intro_moseleftkeydown()==1){
		return 0;
	}
}
void gamestart1_moseleftkeydown(){
    HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
	DWORD mode;
	GetConsoleMode(hStdin, &mode);
	mode &= ~ENABLE_QUICK_EDIT_MODE;
	SetConsoleMode(hStdin, mode);
	while (1) {
		if (KEY_DOWN(VK_LBUTTON)) {
			GetCursorPos(&p);
			ScreenToClient(h, &p);
			gamestartx=p.x;
			gamestarty=p.y;
			if(gamestartx>=10 and gamestartx<=120 and gamestarty>=30 and gamestarty<=70){
				gamemode=0;
				return;
			}else if(gamestartx>=160 and gamestartx<=270 and gamestarty>=30 and gamestarty<=70){
				gamemode=1;
				return;
			}
		}
		Sleep(20);
	}
}
void gamestart2_moseleftkeydown(){
    HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
	DWORD mode;
	GetConsoleMode(hStdin, &mode);
	mode &= ~ENABLE_QUICK_EDIT_MODE;
	SetConsoleMode(hStdin, mode);
	while (1) {
		if (KEY_DOWN(VK_LBUTTON)) {
			GetCursorPos(&p);
			ScreenToClient(h, &p);
			gamestartx=p.x;
			gamestarty=p.y;
			if(gamestartx>=10 and gamestartx<=80 and gamestarty>=30 and gamestarty<=70){
				gamekunnan=1;
				return;
			}else if(gamestartx>=120 and gamestartx<=190 and gamestarty>=30 and gamestarty<=70){
				gamekunnan=2;
				return;
			}else if(gamestartx>=230 and gamestartx<=300 and gamestarty>=30 and gamestarty<=70){
				gamekunnan=3;
				return;
			}else if(gamestartx>=340 and gamestartx<=510 and gamestarty>=30 and gamestarty<=70){
				gamekunnan=4;
				return;
			}
		}
		Sleep(20);
	}
}
int start(){
	white_map();
	output=3;
	gameplayer=1;
	gamerule = 3;
	gamepalce=1;
	SetConsoleTextAttribute(hConsole, BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_INTENSITY);
	system("mode con cols=50 lines=5");
    system("cls");
    cout << "请玩家选择执棋子类型                " << endl;
    cout << "╔══════════╗"<<"   "<<"╔══════════╗"<<endl;
    cout << "║  黑 棋   ║"<<"   "<<"║  白 棋   ║"<<endl;;
    cout << "╚══════════╝"<<"   "<<"╚══════════╝"<<endl;
    gamestart1_moseleftkeydown();
    clearScreen();
    cout << "请玩家选择游戏难度                     " << endl;
	cout << "╔══════╗"<<"   "<<"╔══════╗"<<"   "<<"╔══════╗"<<"   "<<"╔══════╗"<<endl;
	cout << "║ 1 级 ║"<<"   "<<"║ 2 级 ║"<<"   "<<"║ 3 级 ║"<<"   "<<"║ 4 级 ║"<<endl;;
	cout << "╚══════╝"<<"   "<<"╚══════╝"<<"   "<<"╚══════╝"<<"   "<<"╚══════╝"<<endl;
	Sleep(300);
	gamestart2_moseleftkeydown();
	SetConsoleTextAttribute(hConsole, BACKGROUND_RED | BACKGROUND_GREEN );
	system("mode con cols=80 lines=45");
	return 0;
}
int moregame_moseleftkeydown(){
    HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
	DWORD mode;
	GetConsoleMode(hStdin, &mode);
	mode &= ~ENABLE_QUICK_EDIT_MODE;
	SetConsoleMode(hStdin, mode);
	while (1) {
		if (KEY_DOWN(VK_LBUTTON)) {
			GetCursorPos(&p);
			ScreenToClient(h, &p);
			gamestartx=p.x;
			gamestarty=p.y;
			if(gamestartx>=10 and gamestartx<=130 and gamestarty>=830 and gamestarty<=870){
				return 1;
			}else if(gamestartx>=210 and gamestartx<=330 and gamestarty>=830 and gamestarty<=870){
				return 2;
			}
		}
		Sleep(20);
	}
}
int more_game() {
	cout << "╔═══════════╗"<<"       "<<"╔═══════════╗"<<endl;
	cout << "║  再来一局 ║"<<"       "<<"║   离  开  ║"<<endl;;
	cout << "╚═══════════╝"<<"       "<<"╚═══════════╝"<<endl;
	return moregame_moseleftkeydown();
}
int gamestart_loading() { //模拟加载
	SetConsoleTextAttribute(hConsole, FOREGROUND_RED | BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_INTENSITY);
	system("mode con cols=70 lines=25");
	intro();
	clearScreen();
	SetConsoleTextAttribute(hConsole, BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_INTENSITY);
	system("mode con cols=30 lines=3");
	for (int i = 0; i <= 6; i++) {
		cout << "loading ";
		timesleep(90000);
		for (int j = 0; j < 3; j++) {
			cout << ".";
			timesleep(90000);
		}
		clearScreen();
	}
	return 0;
}
int main() {
	gamestart_loading();
	start();
	Game();
	print_win_or_lose();
	gamepalce=more_game();
	while (true) {
		if (gamepalce == 1) {
			start();
			Game();
			print_win_or_lose();
			gamepalce = more_game();
		} else if (gamepalce == 2) {
			break;
		}
	}
	return 0;
}

注意:c++版本代码的介绍与解析详见文章:
1.https://blog.csdn.net/crystal_liu0304/article/details/149313364?spm=1001.2014.3001.5501
2.https://blog.csdn.net/crystal_liu0304/article/details/146923332?spm=1001.2014.3001.5501

Python版本源代码:
 

import pygame
import sys
import numpy as np
import random
import time
from pygame.locals import *

# 初始化pygame
pygame.init()

# 游戏常量
BOARD_SIZE = 19  # 改为19x19棋盘
CELL_SIZE = 30
MARGIN = 50
BUTTON_WIDTH = 120
BUTTON_HEIGHT = 40
BOARD_WIDTH = BOARD_SIZE * CELL_SIZE
BOARD_HEIGHT = BOARD_SIZE * CELL_SIZE
SCREEN_WIDTH = BOARD_WIDTH + 2 * MARGIN
SCREEN_HEIGHT = BOARD_HEIGHT + 2 * MARGIN + 100  # 额外空间用于显示按钮和信息

# 颜色定义
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GRAY = (200, 200, 200)
RED = (255, 0, 0)
GREEN = (0, 128, 0)
BLUE = (0, 0, 255)
BROWN = (165, 42, 42)
LIGHT_BROWN = (222, 184, 135)
DARK_BLUE = (0, 0, 139)
LIGHT_BLUE = (173, 216, 230)

# 创建游戏窗口
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("五子棋游戏 - 19x19")

# 字体
font = pygame.font.SysFont('simhei', 24)
small_font = pygame.font.SysFont('simhei', 18)
large_font = pygame.font.SysFont('simhei', 36)

# 全局变量
gameplayer = 1
qi_p = np.zeros((BOARD_SIZE, BOARD_SIZE), dtype=int)  # 棋盘
return_map = np.zeros((4, BOARD_SIZE, BOARD_SIZE), dtype=int)  # 悔棋缓存
gamerule = 3  # 游戏状态:1为失败,2为胜利,3为正在进行
a, b = 0, 0  # ai对手下棋的x和y坐标
fx = [(1, 1), (1, 0), (0, 1), (1, -1)]
gamemode = 0  # 下棋先后手
output = 3  # 剩余悔棋次数
gamekunnan = 1  # AI难度
gamepalce = 1
gamestartx, gamestarty = 0, 0
ai_first_move_done = False  # 新增:标记AI是否已经完成第一步

# 初始化棋盘
def csh():
    global qi_p, ai_first_move_done
    qi_p = np.zeros((BOARD_SIZE, BOARD_SIZE), dtype=int)
    ai_first_move_done = False  # 重置AI第一步标记

# 清空缓存
def white_map():
    global return_map
    return_map = np.zeros((4, BOARD_SIZE, BOARD_SIZE), dtype=int)

# 将棋盘数据写入缓存
def move_the_map():
    global return_map, qi_p
    for i in range(1, 4):
        return_map[i-1] = return_map[i].copy()
    return_map[3] = qi_p.copy()

# 悔棋后迁移棋盘数据
def if_move_the_map():
    global qi_p, return_map
    qi_p = return_map[2].copy()
    for i in range(3, 0, -1):
        return_map[i] = return_map[i-1].copy()

# 检查指定方向是否有连续n个棋子
def checkDirection(x, y, dx, dy, player, n):
    count = 1
    for i in range(1, n):
        nx = x + i * dx
        ny = y + i * dy
        if 0 <= nx < BOARD_SIZE and 0 <= ny < BOARD_SIZE and qi_p[nx][ny] == player:
            count += 1
        else:
            break
    for i in range(1, n):
        nx = x - i * dx
        ny = y - i * dy
        if 0 <= nx < BOARD_SIZE and 0 <= ny < BOARD_SIZE and qi_p[nx][ny] == player:
            count += 1
        else:
            break
    return count >= n

# 计算周围棋子数
def arnd(x, y):
    cnt = 0
    for i in range(max(0, x-1), min(BOARD_SIZE, x+2)):
        for j in range(max(0, y-1), min(BOARD_SIZE, y+2)):
            if qi_p[i][j] > 0:
                cnt += 1
    return cnt

# 评估函数 - 优化版
def evaluate_position(ai_player):
    human_player = 1 if ai_player == 2 else 2
    score = 0
    
    # 检查是否获胜
    if check_win(ai_player):
        return 1000000
    if check_win(human_player):
        return -1000000
    
    # 评估每个位置
    for i in range(BOARD_SIZE):
        for j in range(BOARD_SIZE):
            if qi_p[i][j] == 0:
                # 空位评估
                continue
            
            player = qi_p[i][j]
            multiplier = 1 if player == ai_player else -1
            
            # 检查四个方向
            for dx, dy in [(1, 0), (0, 1), (1, 1), (1, -1)]:
                # 正向检查
                count = 1
                blocked = False
                for k in range(1, 6):
                    ni, nj = i + k*dx, j + k*dy
                    if 0 <= ni < BOARD_SIZE and 0 <= nj < BOARD_SIZE:
                        if qi_p[ni][nj] == player:
                            count += 1
                        elif qi_p[ni][nj] == 0:
                            break
                        else:
                            blocked = True
                            break
                    else:
                        blocked = True
                        break
                
                # 反向检查
                for k in range(1, 6):
                    ni, nj = i - k*dx, j - k*dy
                    if 0 <= ni < BOARD_SIZE and 0 <= nj < BOARD_SIZE:
                        if qi_p[ni][nj] == player:
                            count += 1
                        elif qi_p[ni][nj] == 0:
                            break
                        else:
                            blocked = True
                            break
                    else:
                        blocked = True
                        break
                
                # 根据连子数和是否被阻挡评分
                if count >= 5:
                    score += multiplier * 100000
                elif count == 4:
                    if not blocked:
                        score += multiplier * 10000  # 活四
                    else:
                        score += multiplier * 1000   # 冲四
                elif count == 3:
                    if not blocked:
                        score += multiplier * 1000   # 活三
                    else:
                        score += multiplier * 100    # 眠三
                elif count == 2:
                    if not blocked:
                        score += multiplier * 100    # 活二
                    else:
                        score += multiplier * 10     # 眠二
                elif count == 1:
                    score += multiplier * 1
    
    return score

# 检查是否获胜
def check_win(player):
    for i in range(BOARD_SIZE):
        for j in range(BOARD_SIZE):
            if qi_p[i][j] == player:
                if checkDirection(i, j, 0, 1, player, 5):
                    return True
                if checkDirection(i, j, 1, 0, player, 5):
                    return True
                if checkDirection(i, j, 1, 1, player, 5):
                    return True
                if checkDirection(i, j, 1, -1, player, 5):
                    return True
    return False

# Alpha-Beta剪枝算法
def alpha_beta(depth, alpha, beta, maximizingPlayer, ai_player):
    human_player = 1 if ai_player == 2 else 2
    
    # 检查游戏是否结束或达到最大深度
    if depth == 0 or check_win(ai_player) or check_win(human_player):
        return evaluate_position(ai_player)
    
    # 获取可能的移动
    moves = []
    for i in range(BOARD_SIZE):
        for j in range(BOARD_SIZE):
            if qi_p[i][j] == 0 and arnd(i, j) > 0:
                moves.append((i, j))
    
    # 如果没有合适的移动,随机选择一个
    if not moves:
        for i in range(BOARD_SIZE):
            for j in range(BOARD_SIZE):
                if qi_p[i][j] == 0:
                    moves.append((i, j))
    
    # 按周围棋子数排序,提高剪枝效率
    moves.sort(key=lambda move: arnd(move[0], move[1]), reverse=True)
    
    if maximizingPlayer:
        maxEval = float('-inf')
        for move in moves:
            qi_p[move[0]][move[1]] = ai_player
            eval_val = alpha_beta(depth - 1, alpha, beta, False, ai_player)
            qi_p[move[0]][move[1]] = 0
            maxEval = max(maxEval, eval_val)
            alpha = max(alpha, eval_val)
            if beta <= alpha:
                break  # Beta剪枝
        return maxEval
    else:
        minEval = float('inf')
        for move in moves:
            qi_p[move[0]][move[1]] = human_player
            eval_val = alpha_beta(depth - 1, alpha, beta, True, ai_player)
            qi_p[move[0]][move[1]] = 0
            minEval = min(minEval, eval_val)
            beta = min(beta, eval_val)
            if beta <= alpha:
                break  # Alpha剪枝
        return minEval

# AI下棋 - 使用Alpha-Beta剪枝
def AI_k(ai):
    bestScore = float('-inf')
    ai_player = 2 if gamemode == 0 else 1
    bestMoves = []
    moves = []
    
    # 获取可能的移动
    for i in range(BOARD_SIZE):
        for j in range(BOARD_SIZE):
            if qi_p[i][j] == 0 and arnd(i, j) > 0:
                moves.append((i, j))
    
    if not moves:
        for i in range(BOARD_SIZE):
            for j in range(BOARD_SIZE):
                if qi_p[i][j] == 0:
                    moves.append((i, j))
    
    # 按周围棋子数排序
    moves.sort(key=lambda move: arnd(move[0], move[1]), reverse=True)
    
    # 根据难度设置搜索深度
    depth = ai
    
    # 使用Alpha-Beta剪枝搜索最佳移动
    for move in moves:
        qi_p[move[0]][move[1]] = ai_player
        currentScore = alpha_beta(depth - 1, float('-inf'), float('inf'), False, ai_player)
        qi_p[move[0]][move[1]] = 0
        
        if currentScore > bestScore:
            bestScore = currentScore
            bestMoves = [move]
        elif currentScore == bestScore:
            bestMoves.append(move)
    
    if bestMoves:
        # 如果有多个最佳移动,选择周围棋子最多的
        bestArnd = -1
        bestMove = bestMoves[0]
        for move in bestMoves:
            currentArnd = arnd(move[0], move[1])
            if currentArnd > bestArnd:
                bestArnd = currentArnd
                bestMove = move
        return bestMove[0], bestMove[1]
    elif moves:
        return moves[0][0], moves[0][1]
    else:
        return 9, 9  # 默认位置

def AI():
    return AI_k(gamekunnan)

# 检查胜负
def win_or_lose():
    player = 1 if gamemode == 0 else 2
    
    if check_win(player):
        return 2
    
    # 检查棋盘是否已满
    fullBoard = True
    for i in range(BOARD_SIZE):
        for j in range(BOARD_SIZE):
            if qi_p[i][j] == 0:
                fullBoard = False
                break
        if not fullBoard:
            break
    
    if fullBoard:
        return 0
    return 3

# 绘制棋盘
def draw_board():
    # 绘制棋盘背景
    screen.fill(LIGHT_BROWN)
    
    # 绘制棋盘网格
    for i in range(BOARD_SIZE):
        # 横线
        pygame.draw.line(screen, BLACK, 
                         (MARGIN, MARGIN + i * CELL_SIZE), 
                         (MARGIN + (BOARD_SIZE-1) * CELL_SIZE, MARGIN + i * CELL_SIZE), 2)
        # 竖线
        pygame.draw.line(screen, BLACK, 
                         (MARGIN + i * CELL_SIZE, MARGIN), 
                         (MARGIN + i * CELL_SIZE, MARGIN + (BOARD_SIZE-1) * CELL_SIZE), 2)
    
    # 绘制棋盘上的九个点 (19x19棋盘标准点位)
    points = [
        (3, 3), (3, 9), (3, 15),
        (9, 3), (9, 9), (9, 15),
        (15, 3), (15, 9), (15, 15)
    ]
    for point in points:
        x, y = point
        pygame.draw.circle(screen, BLACK, 
                          (MARGIN + x * CELL_SIZE, MARGIN + y * CELL_SIZE), 5)
    
    # 绘制棋子
    for i in range(BOARD_SIZE):
        for j in range(BOARD_SIZE):
            if qi_p[i][j] == 1:  # 黑棋
                pygame.draw.circle(screen, BLACK, 
                                  (MARGIN + j * CELL_SIZE, MARGIN + i * CELL_SIZE), 
                                  CELL_SIZE // 2 - 2)
            elif qi_p[i][j] == 2:  # 白棋
                pygame.draw.circle(screen, WHITE, 
                                  (MARGIN + j * CELL_SIZE, MARGIN + i * CELL_SIZE), 
                                  CELL_SIZE // 2 - 2)
                pygame.draw.circle(screen, BLACK, 
                                  (MARGIN + j * CELL_SIZE, MARGIN + i * CELL_SIZE), 
                                  CELL_SIZE // 2 - 2, 1)

# 绘制按钮
def draw_button(text, x, y, width, height, color, hover_color=None, hover=False):
    if hover and hover_color:
        pygame.draw.rect(screen, hover_color, (x, y, width, height))
    else:
        pygame.draw.rect(screen, color, (x, y, width, height))
    pygame.draw.rect(screen, BLACK, (x, y, width, height), 2)
    
    text_surf = font.render(text, True, BLACK)
    text_rect = text_surf.get_rect(center=(x + width // 2, y + height // 2))
    screen.blit(text_surf, text_rect)
    
    return pygame.Rect(x, y, width, height)

# 绘制悔棋按钮
def draw_return_button():
    return draw_button(f"悔棋({output}次)", 
                      SCREEN_WIDTH // 2 - BUTTON_WIDTH // 2, 
                      SCREEN_HEIGHT - 80, 
                      BUTTON_WIDTH, BUTTON_HEIGHT, 
                      GRAY)

# 绘制游戏信息
def draw_game_info():
    # 显示当前玩家
    player_text = "当前回合: " + ("黑棋" if (gamemode == 0 and gameplayer == 1) or (gamemode == 1 and gameplayer == 2) else "白棋")
    player_surf = font.render(player_text, True, BLUE)
    screen.blit(player_surf, (10, SCREEN_HEIGHT - 120))
    
    # 显示游戏状态
    if gamerule == 1:
        state_text = "游戏状态: 你输了"
    elif gamerule == 2:
        state_text = "游戏状态: 你赢了"
    else:
        state_text = "游戏状态: 进行中"
    state_surf = font.render(state_text, True, RED)
    screen.blit(state_surf, (10, SCREEN_HEIGHT - 90))
    
    # 显示AI难度
    difficulty_text = f"AI难度: {gamekunnan}级"
    diff_surf = small_font.render(difficulty_text, True, GREEN)
    screen.blit(diff_surf, (SCREEN_WIDTH - 150, SCREEN_HEIGHT - 120))

# 绘制开始界面
def draw_intro():
    screen.fill(WHITE)
    
    title = font.render("五子棋游戏 - 19x19", True, BLUE)
    screen.blit(title, (SCREEN_WIDTH // 2 - title.get_width() // 2, 50))
    
    rules = [
        "游戏规则:",
        "1. 执黑棋者为先手",
        "2. 棋盘大小为19x19",
        "3. 任意方向连成5子即获胜",
        "4. 点击交叉点下棋",
        "5. 你将与AI对战",
        "注意:使用Alpha-Beta剪枝算法优化AI"
    ]
    
    for i, rule in enumerate(rules):
        rule_surf = small_font.render(rule, True, BLACK)
        screen.blit(rule_surf, (SCREEN_WIDTH // 2 - 200, 100 + i * 30))
    
    # 绘制开始按钮
    start_btn = draw_button("开始游戏", SCREEN_WIDTH // 2 - BUTTON_WIDTH // 2, 
                           SCREEN_HEIGHT - 100, BUTTON_WIDTH, BUTTON_HEIGHT, GREEN)
    
    return start_btn

# 绘制选择界面
def draw_selection(selection_type):
    screen.fill(WHITE)
    
    if selection_type == "color":
        title = font.render("选择执棋颜色", True, BLUE)
        screen.blit(title, (SCREEN_WIDTH // 2 - title.get_width() // 2, 50))
        
        black_btn = draw_button("黑棋(先手)", SCREEN_WIDTH // 2 - BUTTON_WIDTH - 20, 
                               SCREEN_HEIGHT // 2 - BUTTON_HEIGHT // 2, BUTTON_WIDTH, BUTTON_HEIGHT, WHITE, (50, 50, 50))
        white_btn = draw_button("白棋(后手)", SCREEN_WIDTH // 2 + 20, 
                               SCREEN_HEIGHT // 2 - BUTTON_HEIGHT // 2, BUTTON_WIDTH, BUTTON_HEIGHT, WHITE, (220, 220, 220))
        
        return black_btn, white_btn
    else:  # 难度选择
        title = font.render("选择AI难度", True, BLUE)
        screen.blit(title, (SCREEN_WIDTH // 2 - title.get_width() // 2, 50))
        
        btn1 = draw_button("1级", SCREEN_WIDTH // 4 - BUTTON_WIDTH // 2, 
                          SCREEN_HEIGHT // 2 - BUTTON_HEIGHT // 2, BUTTON_WIDTH, BUTTON_HEIGHT, GREEN, (100, 200, 100))
        btn2 = draw_button("2级", SCREEN_WIDTH // 2 - BUTTON_WIDTH // 2, 
                          SCREEN_HEIGHT // 2 - BUTTON_HEIGHT // 2, BUTTON_WIDTH, BUTTON_HEIGHT, GREEN, (100, 200, 100))
        btn3 = draw_button("3级", 3 * SCREEN_WIDTH // 4 - BUTTON_WIDTH // 2, 
                          SCREEN_HEIGHT // 2 - BUTTON_HEIGHT // 2, BUTTON_WIDTH, BUTTON_HEIGHT, GREEN, (100, 200, 100))
        
        return btn1, btn2, btn3

# 绘制游戏结束界面
def draw_game_over():
    overlay = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT), pygame.SRCALPHA)
    overlay.fill((0, 0, 0, 128))  # 半透明黑色
    screen.blit(overlay, (0, 0))
    
    if gamerule == 1:
        result_text = "你输了!"
        color = RED
    else:
        result_text = "你赢了!"
        color = GREEN
    
    result_surf = font.render(result_text, True, color)
    screen.blit(result_surf, (SCREEN_WIDTH // 2 - result_surf.get_width() // 2, SCREEN_HEIGHT // 2 - 50))
    
    again_btn = draw_button("再来一局", SCREEN_WIDTH // 2 - BUTTON_WIDTH - 10, 
                           SCREEN_HEIGHT // 2 + 20, BUTTON_WIDTH, BUTTON_HEIGHT, GREEN, (100, 200, 100))
    quit_btn = draw_button("退出游戏", SCREEN_WIDTH // 2 + 10, 
                          SCREEN_HEIGHT // 2 + 20, BUTTON_WIDTH, BUTTON_HEIGHT, RED, (200, 100, 100))
    
    return again_btn, quit_btn

# 显示AI思考中
def show_ai_thinking():
    thinking_text = font.render("AI思考中...", True, BLUE)
    screen.blit(thinking_text, (SCREEN_WIDTH // 2 - thinking_text.get_width() // 2, SCREEN_HEIGHT - 40))
    pygame.display.flip()

# 绘制加载界面
def draw_loading(progress, dots, tip_index):
    # 绘制渐变背景
    for i in range(SCREEN_HEIGHT):
        color_ratio = i / SCREEN_HEIGHT
        color = (
            int(LIGHT_BLUE[0] * (1 - color_ratio) + DARK_BLUE[0] * color_ratio),
            int(LIGHT_BLUE[1] * (1 - color_ratio) + DARK_BLUE[1] * color_ratio),
            int(LIGHT_BLUE[2] * (1 - color_ratio) + DARK_BLUE[2] * color_ratio)
        )
        pygame.draw.line(screen, color, (0, i), (SCREEN_WIDTH, i))
    
    # 绘制标题
    title = large_font.render("五子棋游戏", True, WHITE)
    screen.blit(title, (SCREEN_WIDTH // 2 - title.get_width() // 2, SCREEN_HEIGHT // 3))
    
    # 绘制加载文本
    loading_text = font.render("Loading" + "." * dots, True, WHITE)
    screen.blit(loading_text, (SCREEN_WIDTH // 2 - loading_text.get_width() // 2, SCREEN_HEIGHT // 2))
    
    # 绘制进度条背景
    progress_bar_bg = pygame.Rect(SCREEN_WIDTH // 4, SCREEN_HEIGHT // 2 + 50, SCREEN_WIDTH // 2, 20)
    pygame.draw.rect(screen, (50, 50, 50), progress_bar_bg)
    
    # 绘制进度条
    progress_bar = pygame.Rect(SCREEN_WIDTH // 4, SCREEN_HEIGHT // 2 + 50, (SCREEN_WIDTH // 2) * progress, 20)
    pygame.draw.rect(screen, GREEN, progress_bar)
    
    # 绘制进度百分比
    percent_text = font.render(f"{int(progress * 100)}%", True, WHITE)
    screen.blit(percent_text, (SCREEN_WIDTH // 2 - percent_text.get_width() // 2, SCREEN_HEIGHT // 2 + 80))
    
    # 绘制提示信息
    tips = [
        "正在初始化游戏引擎...",
        "正在加载AI算法...",
        "正在准备棋盘数据...",
        "正在优化游戏性能...",
        "游戏准备完成!"
    ]
    
    # 使用传递过来的提示索引,确保"游戏准备完成!"只在100%时显示
    tip_text = small_font.render(tips[tip_index], True, WHITE)
    screen.blit(tip_text, (SCREEN_WIDTH // 2 - tip_text.get_width() // 2, SCREEN_HEIGHT // 2 + 120))
    
    # 绘制版权信息
    copyright_text = small_font.render("基于Alpha-Beta剪枝算法优化", True, (200, 200, 200))
    screen.blit(copyright_text, (SCREEN_WIDTH // 2 - copyright_text.get_width() // 2, SCREEN_HEIGHT - 50))
# 主游戏循环
def main():
    global qi_p, return_map, gamerule, a, b, gamemode, output, gamekunnan, gamepalce, gameplayer, ai_first_move_done
    
    # 游戏状态
    game_state = "loading"  # loading, intro, selection_color, selection_difficulty, playing, game_over
    
    # 加载界面变量
    loading_start_time = time.time()
    loading_duration = 8  # 修正注释与实际值不一致的问题,改为8秒
    dots_count = 0
    last_dots_update = 0  # 上次更新点点点的时间
    loading_complete_time = None  # 新增:记录加载完成的时间
    
    # 初始化
    csh()
    white_map()
    
    # 主循环
    running = True
    clock = pygame.time.Clock()  # 创建时钟对象控制帧率
    
    while running:
        current_time = time.time()
        mouse_pos = pygame.mouse.get_pos()
        mouse_buttons = pygame.mouse.get_pressed()
        
        # 处理加载界面的动态效果
        if game_state == "loading":
            elapsed_time = current_time - loading_start_time
            progress = min(elapsed_time / loading_duration, 1.0)
            
            # 更新点点点动画 - 每0.5秒更新一次
            if current_time - last_dots_update > 0.5:  # 修正注释与实际值不一致的问题
                dots_count = (dots_count + 1) % 4
                last_dots_update = current_time
            
            # 检查加载是否完成
            if progress >= 1.0:
                # 如果还没有记录完成时间,则记录
                if loading_complete_time is None:
                    loading_complete_time = current_time
                # 如果记录完成时间已经过了1秒,则切换状态
                elif current_time - loading_complete_time >= 1.0:
                    game_state = "intro"
        
        for event in pygame.event.get():
            if event.type == QUIT:
                running = False
            
            if event.type == MOUSEBUTTONDOWN:
                if game_state == "intro":
                    start_btn = draw_intro()
                    if start_btn.collidepoint(mouse_pos):
                        game_state = "selection_color"
                
                elif game_state == "selection_color":
                    black_btn, white_btn = draw_selection("color")
                    if black_btn.collidepoint(mouse_pos):
                        gamemode = 0  # 黑棋先手
                        game_state = "selection_difficulty"
                    elif white_btn.collidepoint(mouse_pos):
                        gamemode = 1  # 白棋后手
                        game_state = "selection_difficulty"
                
                elif game_state == "selection_difficulty":
                    btn1, btn2, btn3 = draw_selection("difficulty")
                    if btn1.collidepoint(mouse_pos):
                        gamekunnan = 1
                        game_state = "playing"
                    elif btn2.collidepoint(mouse_pos):
                        gamekunnan = 2
                        game_state = "playing"
                    elif btn3.collidepoint(mouse_pos):
                        gamekunnan = 3
                        game_state = "playing"
                
                elif game_state == "playing":
                    # 检查是否点击了悔棋按钮
                    return_btn = draw_return_button()
                    if return_btn.collidepoint(mouse_pos) and output > 0:
                        output -= 1
                        if_move_the_map()
                    
                    # 检查是否点击了棋盘
                    if (MARGIN <= mouse_pos[0] <= MARGIN + (BOARD_SIZE-1) * CELL_SIZE and
                        MARGIN <= mouse_pos[1] <= MARGIN + (BOARD_SIZE-1) * CELL_SIZE):
                        
                        # 计算棋盘坐标
                        x = round((mouse_pos[1] - MARGIN) / CELL_SIZE)
                        y = round((mouse_pos[0] - MARGIN) / CELL_SIZE)
                        
                        if 0 <= x < BOARD_SIZE and 0 <= y < BOARD_SIZE and qi_p[x][y] == 0:
                            if gamemode == 0:  # 玩家执黑
                                qi_p[x][y] = 1
                                if win_or_lose() == 2:
                                    gamerule = 2
                                    game_state = "game_over"
                                else:
                                    # AI下棋
                                    show_ai_thinking()
                                    a, b = AI()
                                    qi_p[a][b] = 2
                                    if check_win(2):
                                        gamerule = 1
                                        game_state = "game_over"
                                    move_the_map()
                            
                            else:  # 玩家执白
                                # 玩家下棋
                                qi_p[x][y] = 2
                                if win_or_lose() == 2:
                                    gamerule = 2
                                    game_state = "game_over"
                                else:
                                    # AI下棋
                                    show_ai_thinking()
                                    a, b = AI()
                                    qi_p[a][b] = 1
                                    if check_win(1):
                                        gamerule = 1
                                        game_state = "game_over"
                                    move_the_map()
                
                elif game_state == "game_over":
                    again_btn, quit_btn = draw_game_over()
                    if again_btn.collidepoint(mouse_pos):
                        # 重置游戏
                        csh()
                        white_map()
                        output = 3
                        gameplayer = 1
                        gamerule = 3
                        game_state = "selection_color"
                    elif quit_btn.collidepoint(mouse_pos):
                        running = False
        
        # 处理白棋模式下AI先手
        if game_state == "playing" and gamemode == 1 and not ai_first_move_done:
            # AI先下第一步,直接下在中间位置(9,9)
            a, b = 9, 9
            qi_p[a][b] = 1
            ai_first_move_done = True
            if check_win(1):
                gamerule = 1
                game_state = "game_over"
            move_the_map()
        
        # 绘制当前状态
        if game_state == "loading":
            # 根据实际进度传递提示信息索引
            # 只有当进度达到100%时才显示"游戏准备完成!"
            tip_index = min(int(progress * 4), 3)  # 进度0-80%时显示前4条提示
            if progress >= 1.0:
                tip_index = 4  # 进度100%时显示完成提示
            draw_loading(progress, dots_count, tip_index)  # 传递提示索引
        elif game_state == "intro":
            draw_intro()
        elif game_state == "selection_color":
            draw_selection("color")
        elif game_state == "selection_difficulty":
            draw_selection("difficulty")
        elif game_state == "playing":
            draw_board()
            draw_return_button()
            draw_game_info()
        elif game_state == "game_over":
            draw_board()
            draw_game_info()
            draw_game_over()
        
        pygame.display.flip()
        clock.tick(60)  # 限制帧率为60FPS
    
    pygame.quit()
    sys.exit()
if __name__ == "__main__":
    main()

Python版本程序简介与分析:

一、程序框架简介

        这个五子棋游戏代码整体上基于 Python 的 Pygame 库搭建,通过一系列函数来实现游戏从初始化、界面绘制到游戏流程控制以及人机对战等多个功能。

1.初始化

  • 代码首先调用 pygame.init() 对 Pygame 进行初始化操作,为后续游戏窗口创建、图形绘制等功能打下基础。
  • 定义了诸多游戏相关的常量,例如棋盘大小 BOARD_SIZE 设定为 19(对应 19x19 的五子棋棋盘),还有棋盘格子大小 CELL_SIZE、边距 MARGIN、按钮尺寸等,这些常量用于精确控制游戏界面的布局与显示效果。
  • 同时初始化了各种颜色变量,用于区分不同的元素(如棋子颜色、棋盘背景颜色、按钮颜色等),以及创建用于显示文字的字体对象。
  • 还声明了多个全局变量,像 gameplayer 用于记录当前玩家,qi_p 用于存储棋盘状态,return_map 作为悔棋缓存等,这些全局变量在整个游戏流程中起着关键的数据存储和状态记录作用。
# 初始化pygame
pygame.init()

# 游戏常量
BOARD_SIZE = 19  # 19x19棋盘
CELL_SIZE = 30
MARGIN = 50
BUTTON_WIDTH = 120
BUTTON_HEIGHT = 40
BOARD_WIDTH = BOARD_SIZE * CELL_SIZE
BOARD_HEIGHT = BOARD_SIZE * CELL_SIZE
SCREEN_WIDTH = BOARD_WIDTH + 2 * MARGIN
SCREEN_HEIGHT = BOARD_HEIGHT + 2 * MARGIN + 100  # 额外空间用于显示按钮和信息

# 颜色定义
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GRAY = (200, 200, 200)
RED = (255, 0, 0)
GREEN = (0, 128, 0)
BLUE = (0, 0, 255)
BROWN = (165, 42, 42)
LIGHT_BROWN = (222, 184, 135)
DARK_BLUE = (0, 0, 139)
LIGHT_BLUE = (173, 216, 230)

# 创建游戏窗口
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("五子棋游戏 - 19x19")

# 字体
font = pygame.font.SysFont('simhei', 24)
small_font = pygame.font.SysFont('simhei', 18)
large_font = pygame.font.SysFont('simhei', 36)

# 全局变量
gameplayer = 1
qi_p = np.zeros((BOARD_SIZE, BOARD_SIZE), dtype=int)  # 棋盘
return_map = np.zeros((4, BOARD_SIZE, BOARD_SIZE), dtype=int)  # 悔棋缓存
gamerule = 3  # 游戏状态:1为失败,2为胜利,3为正在进行
a, b = 0, 0  # ai对手下棋的x和y坐标
fx = [(1, 1), (1, 0), (0, 1), (1, -1)]
gamemode = 0  # 下棋先后手
output = 3  # 剩余悔棋次数
gamekunnan = 1  # AI难度
ai_first_move_done = False  # 标记AI是否已经完成第一步

2.界面绘制相关函数

  • 有多个专门绘制不同界面元素的函数,比如 draw_board() 函数,负责绘制棋盘的背景、网格以及棋盘上的九个标准点位,并且根据棋盘状态绘制对应的黑棋和白棋棋子,让整个棋盘可视化呈现出来。
  • draw_button() 函数用于绘制各种按钮(如开始游戏按钮、悔棋按钮、选择难度按钮等),可以设置按钮的文本、位置、颜色以及鼠标悬停效果等,使游戏交互更加友好。
  • 还有针对不同游戏阶段界面的绘制函数,像 draw_intro() 绘制游戏开始界面展示游戏规则等信息,draw_selection() 绘制选择执棋颜色和 AI 难度的界面,draw_game_over() 绘制游戏结束界面提示输赢并提供再来一局或者退出游戏的选项等。
# 绘制棋盘
def draw_board():
    # 绘制棋盘背景
    screen.fill(LIGHT_BROWN)
    
    # 绘制棋盘网格
    for i in range(BOARD_SIZE):
        # 横线
        pygame.draw.line(screen, BLACK, 
                         (MARGIN, MARGIN + i * CELL_SIZE), 
                         (MARGIN + (BOARD_SIZE-1) * CELL_SIZE, MARGIN + i * CELL_SIZE), 2)
        # 竖线
        pygame.draw.line(screen, BLACK, 
                         (MARGIN + i * CELL_SIZE, MARGIN), 
                         (MARGIN + i * CELL_SIZE, MARGIN + (BOARD_SIZE-1) * CELL_SIZE), 2)
    
    # 绘制棋盘上的九个点 (19x19棋盘标准点位)
    points = [
        (3, 3), (3, 9), (3, 15),
        (9, 3), (9, 9), (9, 15),
        (15, 3), (15, 9), (15, 15)
    ]
    for point in points:
        x, y = point
        pygame.draw.circle(screen, BLACK, 
                          (MARGIN + x * CELL_SIZE, MARGIN + y * CELL_SIZE), 5)
    
    # 绘制棋子
    for i in range(BOARD_SIZE):
        for j in range(BOARD_SIZE):
            if qi_p[i][j] == 1:  # 黑棋
                pygame.draw.circle(screen, BLACK, 
                                  (MARGIN + j * CELL_SIZE, MARGIN + i * CELL_SIZE), 
                                  CELL_SIZE // 2 - 2)
            elif qi_p[i][j] == 2:  # 白棋
                pygame.draw.circle(screen, WHITE, 
                                  (MARGIN + j * CELL_SIZE, MARGIN + i * CELL_SIZE), 
                                  CELL_SIZE // 2 - 2)
                pygame.draw.circle(screen, BLACK, 
                                  (MARGIN + j * CELL_SIZE, MARGIN + i * CELL_SIZE), 
                                  CELL_SIZE // 2 - 2, 1)

# 绘制按钮
def draw_button(text, x, y, width, height, color, hover_color=None, hover=False):
    if hover and hover_color:
        pygame.draw.rect(screen, hover_color, (x, y, width, height))
    else:
        pygame.draw.rect(screen, color, (x, y, width, height))
    pygame.draw.rect(screen, BLACK, (x, y, width, height), 2)
    
    text_surf = font.render(text, True, BLACK)
    text_rect = text_surf.get_rect(center=(x + width // 2, y + height // 2))
    screen.blit(text_surf, text_rect)
    
    return pygame.Rect(x, y, width, height)

3.游戏逻辑与控制函数

  • 函数 csh() 用于初始化棋盘,将棋盘数据重置为全 0 的初始状态。
  • white_map() 用于清空悔棋缓存,方便后续准确记录悔棋操作时的棋盘数据变化。
  • move_the_map() 和 if_move_the_map() 这两个函数实现了将棋盘数据写入缓存以及悔棋后迁移棋盘数据的功能,保障了悔棋操作的正确实现。
  • 核心的 main() 函数则是整个游戏的主循环,通过不断获取用户输入事件(如鼠标点击、退出操作等),并根据当前游戏状态(如加载中、开始界面、游戏进行中、游戏结束等)来调用相应的绘制函数和执行对应的游戏逻辑,例如判断输赢、处理玩家下棋和 AI 下棋等操作,同时控制游戏的帧率来保证游戏运行的流畅性。
# 初始化棋盘
def csh():
    global qi_p, ai_first_move_done
    qi_p = np.zeros((BOARD_SIZE, BOARD_SIZE), dtype=int)
    ai_first_move_done = False  # 重置AI第一步标记

# 清空缓存
def white_map():
    global return_map
    return_map = np.zeros((4, BOARD_SIZE, BOARD_SIZE), dtype=int)

# 将棋盘数据写入缓存
def move_the_map():
    global return_map, qi_p
    for i in range(1, 4):
        return_map[i-1] = return_map[i].copy()
    return_map[3] = qi_p.copy()

# 悔棋后迁移棋盘数据
def if_move_the_map():
    global qi_p, return_map
    qi_p = return_map[2].copy()
    for i in range(3, 0, -1):
        return_map[i] = return_map[i-1].copy()

# 主游戏循环
def main():
    global qi_p, return_map, gamerule, a, b, gamemode, output, gamekunnan, gamepalce, gameplayer, ai_first_move_done
    
    # 游戏状态
    game_state = "loading"  # loading, intro, selection_color, selection_difficulty, playing, game_over
    
    # 加载界面变量
    loading_start_time = time.time()
    loading_duration = 8  # 加载时长设置为8秒
    dots_count = 0
    last_dots_update = 0  # 上次更新点点点的时间
    loading_complete_time = None  # 记录加载完成的时间
    
    # 初始化
    csh()
    white_map()
    
    # 主循环
    running = True
    clock = pygame.time.Clock()  # 创建时钟对象控制帧率
    
    while running:
        current_time = time.time()
        mouse_pos = pygame.mouse.get_pos()
        mouse_buttons = pygame.mouse.get_pressed()
        
        # 处理加载界面的动态效果
        if game_state == "loading":
            elapsed_time = current_time - loading_start_time
            progress = min(elapsed_time / loading_duration, 1.0)
            
            # 更新点点点动画 - 每0.5秒更新一次
            if current_time - last_dots_update > 0.5:
                dots_count = (dots_count + 1) % 4
                last_dots_update = current_time
            
            # 检查加载是否完成
            if progress >= 1.0:
                # 如果还没有记录完成时间,则记录
                if loading_complete_time is None:
                    loading_complete_time = current_time
                # 如果记录完成时间已经过了1秒,则切换状态
                elif current_time - loading_complete_time >= 1.0:
                    game_state = "intro"
        
        for event in pygame.event.get():
            if event.type == QUIT:
                running = False
            
            if event.type == MOUSEBUTTONDOWN:
                if game_state == "intro":
                    start_btn = draw_intro()
                    if start_btn.collidepoint(mouse_pos):
                        game_state = "selection_color"
                
                elif game_state == "selection_color":
                    black_btn, white_btn = draw_selection("color")
                    if black_btn.collidepoint(mouse_pos):
                        gamemode = 0  # 黑棋先手
                        game_state = "selection_difficulty"
                    elif white_btn.collidepoint(mouse_pos):
                        gamemode = 1  # 白棋后手
                        game_state = "selection_difficulty"
                
                elif game_state == "selection_difficulty":
                    btn1, btn2, btn3 = draw_selection("difficulty")
                    if btn1.collidepoint(mouse_pos):
                        gamekunnan = 1
                        game_state = "playing"
                    elif btn2.collidepoint(mouse_pos):
                        gamekunnan = 2
                        game_state = "playing"
                    elif btn3.collidepoint(mouse_pos):
                        gamekunnan = 3
                        game_state = "playing"
                
                elif game_state == "playing":
                    # 检查是否点击了悔棋按钮
                    return_btn = draw_return_button()
                    if return_btn.collidepoint(mouse_pos) and output > 0:
                        output -= 1
                        if_move_the_map()
                    
                    # 检查是否点击了棋盘
                    if (MARGIN <= mouse_pos[0] <= MARGIN + (BOARD_SIZE-1) * CELL_SIZE and
                        MARGIN <= mouse_pos[1] <= MARGIN + (BOARD_SIZE-1) * CELL_SIZE):
                        
                        # 计算棋盘坐标
                        x = round((mouse_pos[1] - MARGIN) / CELL_SIZE)
                        y = round((mouse_pos[0] - MARGIN) / CELL_SIZE)
                        
                        if 0 <= x < BOARD_SIZE and 0 <= y < BOARD_SIZE and qi_p[x][y] == 0:
                            if gamemode == 0:  # 玩家执黑
                                qi_p[x][y] = 1
                                if win_or_lose() == 2:
                                    gamerule = 2
                                    game_state = "game_over"
                                else:
                                    # AI下棋
                                    show_ai_thinking()
                                    a, b = AI()
                                    qi_p[a][b] = 2
                                    if check_win(2):
                                        gamerule = 1
                                        game_state = "game_over"
                                    move_the_map()
                            
                            else:  # 玩家执白
                                # 玩家下棋
                                qi_p[x][y] = 2
                                if win_or_lose() == 2:
                                    gamerule = 2
                                    game_state = "game_over"
                                else:
                                    # AI下棋
                                    show_ai_thinking()
                                    a, b = AI()
                                    qi_p[a][b] = 1
                                    if check_win(1):
                                        gamerule = 1
                                        game_state = "game_over"
                                    move_the_map()
                
                elif game_state == "game_over":
                    again_btn, quit_btn = draw_game_over()
                    if again_btn.collidepoint(mouse_pos):
                        # 重置游戏
                        csh()
                        white_map()
                        output = 3
                        gameplayer = 1
                        gamerule = 3
                        game_state = "selection_color"
                    elif quit_btn.collidepoint(mouse_pos):
                        running = False
        
        # 处理白棋模式下AI先手
        if game_state == "playing" and gamemode == 1 and not ai_first_move_done:
            # AI先下第一步,直接下在中间位置(9,9)
            a, b = 9, 9
            qi_p[a][b] = 1
            ai_first_move_done = True
            if check_win(1):
                gamerule = 1
                game_state = "game_over"
            move_the_map()
        
        # 绘制当前状态
        if game_state == "loading":
            tip_index = min(int(progress * 4), 3)  # 根据进度显示不同提示
            if progress >= 1.0:
                tip_index = 4  # 进度100%时显示完成提示
            draw_loading(progress, dots_count, tip_index)
        elif game_state == "intro":
            draw_intro()
        elif game_state == "selection_color":
            draw_selection("color")
        elif game_state == "selection_difficulty":
            draw_selection("difficulty")
        elif game_state == "playing":
            draw_board()
            draw_return_button()
            draw_game_info()
        elif game_state == "game_over":
            draw_board()
            draw_game_info()
            draw_game_over()
        
        pygame.display.flip()
        clock.tick(60)  # 限制帧率为60FPS
    
    pygame.quit()
    sys.exit()
    

二、算法实现分析

1.胜负判断算法

        在 check_win() 函数中,通过遍历棋盘的每一个位置,针对每个有棋子的位置,分别向四个方向(横向、纵向、正斜向、反斜向)检查是否有连续的 5 颗同色棋子,只要在某个方向上满足条件,则判定对应颜色的玩家获胜。这是通过不断调用 checkDirection() 函数来检查指定方向上连续棋子数量是否达到 5 实现的,逻辑清晰直接,能准确判断游戏的胜负状态。

# 检查指定方向是否有连续n个棋子
def checkDirection(x, y, dx, dy, player, n):
    count = 1
    for i in range(1, n):
        nx = x + i * dx
        ny = y + i * dy
        if 0 <= nx < BOARD_SIZE and 0 <= ny < BOARD_SIZE and qi_p[nx][ny] == player:
            count += 1
        else:
            break
    for i in range(1, n):
        nx = x - i * dx
        ny = y - i * dy
        if 0 <= nx < BOARD_SIZE and 0 <= ny < BOARD_SIZE and qi_p[nx][ny] == player:
            count += 1
        else:
            break
    return count >= n

# 检查是否获胜
def check_win(player):
    for i in range(BOARD_SIZE):
        for j in range(BOARD_SIZE):
            if qi_p[i][j] == player:
                # 检查四个方向是否有连续5个棋子
                if checkDirection(i, j, 0, 1, player, 5):  # 水平
                    return True
                if checkDirection(i, j, 1, 0, player, 5):  # 垂直
                    return True
                if checkDirection(i, j, 1, 1, player, 5):  # 对角线
                    return True
                if checkDirection(i, j, 1, -1, player, 5):  # 反对角线
                    return True
    return False

2.评估函数

    evaluate_position() 函数是用于评估当前棋盘局面对于 AI 一方的优劣程度的关键函数。它首先会检查是否有一方获胜,如果 AI 方获胜则返回一个极大值(如 1000000),如果人类玩家获胜则返回极小值(如 -1000000)。然后对于棋盘上的每一个空位,会依次检查四个方向上棋子的连子情况(包括活四、冲四、活三、眠三、活二、眠二等不同状态),根据连子数和是否被阻挡等情况来给相应位置打分,并且根据是 AI 棋子还是人类玩家棋子乘以对应的正负系数,最后汇总所有位置的分数来综合评估整个棋盘局面,为 AI 决策提供重要参考依据。

# 评估函数 - 优化版
def evaluate_position(ai_player):
    human_player = 1 if ai_player == 2 else 2
    score = 0
    
    # 检查是否获胜
    if check_win(ai_player):
        return 1000000
    if check_win(human_player):
        return -1000000
    
    # 评估每个位置
    for i in range(BOARD_SIZE):
        for j in range(BOARD_SIZE):
            if qi_p[i][j] == 0:
                # 空位评估
                continue
            
            player = qi_p[i][j]
            multiplier = 1 if player == ai_player else -1
            
            # 检查四个方向
            for dx, dy in [(1, 0), (0, 1), (1, 1), (1, -1)]:
                # 正向检查
                count = 1
                blocked = False
                for k in range(1, 6):
                    ni, nj = i + k*dx, j + k*dy
                    if 0 <= ni < BOARD_SIZE and 0 <= nj < BOARD_SIZE:
                        if qi_p[ni][nj] == player:
                            count += 1
                        elif qi_p[ni][nj] == 0:
                            break
                        else:
                            blocked = True
                            break
                    else:
                        blocked = True
                        break
                
                # 反向检查
                for k in range(1, 6):
                    ni, nj = i - k*dx, j - k*dy
                    if 0 <= ni < BOARD_SIZE and 0 <= nj < BOARD_SIZE:
                        if qi_p[ni][nj] == player:
                            count += 1
                        elif qi_p[ni][nj] == 0:
                            break
                        else:
                            blocked = True
                            break
                    else:
                        blocked = True
                        break
                
                # 根据连子数和是否被阻挡评分
                if count >= 5:
                    score += multiplier * 100000
                elif count == 4:
                    if not blocked:
                        score += multiplier * 10000  # 活四
                    else:
                        score += multiplier * 1000   # 冲四
                elif count == 3:
                    if not blocked:
                        score += multiplier * 1000   # 活三
                    else:
                        score += multiplier * 100    # 眠三
                elif count == 2:
                    if not blocked:
                        score += multiplier * 100    # 活二
                    else:
                        score += multiplier * 10     # 眠二
                elif count == 1:
                    score += multiplier * 1
    
    return score

3.AI下棋决策算法

        在 AI_k() 函数以及其调用的 alpha_beta() 函数中实现了 AI 下棋的智能决策逻辑。首先会获取当前棋盘上所有可能的合法移动位置(考虑周围有棋子的空位等情况),然后按照周围棋子数对这些位置进行排序,目的是优先搜索更有价值的位置来提高效率。接着根据设定的 AI 难度来确定搜索深度,使用 alpha_beta() 函数基于 α-β 剪枝算法进行搜索最佳移动。在 alpha_beta() 函数内部,通过递归的方式不断展开搜索树,模拟不同的下棋步骤以及后续局面,根据极大极小算法思想,在搜索过程中交替站在 AI 方(最大化得分)和人类玩家方(最小化得分)的角度进行评估,并且利用 α-β 剪枝规则,当发现某个节点的子树已经不可能影响到当前的最优决策时,直接剪掉该子树,避免不必要的搜索,大大提高了搜索效率,最终确定 AI 的最佳下棋位置。
 

# Alpha-Beta剪枝算法
def alpha_beta(depth, alpha, beta, maximizingPlayer, ai_player):
    human_player = 1 if ai_player == 2 else 2
    
    # 检查游戏是否结束或达到最大深度
    if depth == 0 or check_win(ai_player) or check_win(human_player):
        return evaluate_position(ai_player)
    
    # 获取可能的移动
    moves = []
    for i in range(BOARD_SIZE):
        for j in range(BOARD_SIZE):
            if qi_p[i][j] == 0 and arnd(i, j) > 0:
                moves.append((i, j))
    
    # 如果没有合适的移动,随机选择一个
    if not moves:
        for i in range(BOARD_SIZE):
            for j in range(BOARD_SIZE):
                if qi_p[i][j] == 0:
                    moves.append((i, j))
    
    # 按周围棋子数排序,提高剪枝效率
    moves.sort(key=lambda move: arnd(move[0], move[1]), reverse=True)
    
    if maximizingPlayer:
        maxEval = float('-inf')
        for move in moves:
            qi_p[move[0]][move[1]] = ai_player
            eval_val = alpha_beta(depth - 1, alpha, beta, False, ai_player)
            qi_p[move[0]][move[1]] = 0
            maxEval = max(maxEval, eval_val)
            alpha = max(alpha, eval_val)
            if beta <= alpha:
                break  # Beta剪枝
        return maxEval
    else:
        minEval = float('inf')
        for move in moves:
            qi_p[move[0]][move[1]] = human_player
            eval_val = alpha_beta(depth - 1, alpha, beta, True, ai_player)
            qi_p[move[0]][move[1]] = 0
            minEval = min(minEval, eval_val)
            beta = min(beta, eval_val)
            if beta <= alpha:
                break  # Alpha剪枝
        return minEval

# AI下棋 - 使用Alpha-Beta剪枝
def AI_k(ai):
    bestScore = float('-inf')
    ai_player = 2 if gamemode == 0 else 1
    bestMoves = []
    moves = []
    
    # 获取可能的移动
    for i in range(BOARD_SIZE):
        for j in range(BOARD_SIZE):
            if qi_p[i][j] == 0 and arnd(i, j) > 0:
                moves.append((i, j))
    
    # 按周围棋子数排序
    moves.sort(key=lambda move: arnd(move[0], move[1]), reverse=True)
    
    # 根据难度设置搜索深度
    depth = ai
    
    # 使用Alpha-Beta剪枝搜索最佳移动
    for move in moves:
        qi_p[move[0]][move[1]] = ai_player
        currentScore = alpha_beta(depth - 1, float('-inf'), float('inf'), False, ai_player)
        qi_p[move[0]][move[1]] = 0
        
        if currentScore > bestScore:
            bestScore = currentScore
            bestMoves = [move]
        elif currentScore == bestScore:
            bestMoves.append(move)
    
    # 选择最佳移动
    if bestMoves:
        # 如果有多个最佳移动,选择周围棋子最多的
        bestArnd = -1
        bestMove = bestMoves[0]
        for move in bestMoves:
            currentArnd = arnd(move[0], move[1])
            if currentArnd > bestArnd:
                bestArnd = currentArnd
                bestMove = move
        return bestMove[0], bestMove[1]
    elif moves:
        return moves[0][0], moves[0][1]
    else:
        return 9, 9  # 默认位置

四、α-β 剪枝算法与极大极小算法简介及在本程序中的运用

1.极大极小算法简介

        极大极小算法是一种在博弈类游戏中常用的决策算法,它的核心思想是基于博弈双方的对抗性。在五子棋游戏中,对于 AI 和人类玩家这两个对抗方,AI 希望选择能使自己得分最大的走法(最大化),而人类玩家则会选择让 AI 得分最小的走法(最小化)。算法通过递归地构建搜索树,一层一层地模拟双方可能的走法和后续局面,从最底层的叶子节点(游戏结束局面或者达到搜索深度的局面)向上回溯,不断更新每个节点对应的最大最小值,最终确定当前局面下 AI 的最佳决策,也就是能让自己得分最大的走法,同时考虑到人类玩家的最优应对策略。

2.α-β 剪枝算法简介

        α-β 剪枝算法是对极大极小算法的一种优化改进。在极大极小算法构建搜索树的过程中,会存在很多不必要的搜索分支,α-β 剪枝算法通过记录每个节点的 α 值(当前节点的最大可能值)和 β 值(当前节点的最小可能值),在搜索过程中进行比较判断,如果发现某个子树的搜索结果已经不可能影响到当前节点的最大最小值(也就是满足 α≥β 的情况),就可以直接剪掉该子树,不用继续搜索其剩余的分支,从而有效减少搜索的节点数量,提高算法的搜索效率,让 AI 能在更短时间内做出较好的决策。

3.在本程序中的运用

        在本五子棋程序的 alpha_beta() 函数中充分运用了这两种算法。从整体逻辑上,是基于极大极小算法的思想,在递归搜索过程中,根据当前是 AI 方(最大化玩家)还是人类玩家方(最小化玩家)来分别尝试不同的走法并评估局面得分。而在这个过程中,通过记录 α 和 β 值,在每次扩展新的子节点(尝试新的走法)时,判断是否满足剪枝条件,如果满足就及时进行 α-β 剪枝操作,避免了对大量无效分支的搜索。例如在搜索 AI 最佳走法时,一旦发现某个分支的评估值使得 β 值小于等于 α 值,就意味着这个分支后续的搜索结果不会影响到当前找到的最佳决策,便可以直接剪掉该分支,以此提高 AI 在棋盘局面评估和下棋决策上的效率,使得游戏中的 AI 能更快且更合理地做出下棋动作。

五、总结

        通过上述对这个五子棋游戏代码的详细解析,我们可以看到一个完整的游戏程序背后涉及到的多方面知识,从界面绘制到游戏逻辑控制,再到核心算法的运用。尤其是 α-β 剪枝算法与极大极小算法的结合,为游戏中的 AI 赋予了智能决策的能力,让人机对战更加有趣和富有挑战性。希望这篇文章能帮助大家更好地理解相关知识,也欢迎大家一起交流探讨和对代码进行改进完善。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐