AI Backgammon - super improved version

The improved version of AI backgammon is coming~~
We found that if the original version of AI backgammon is adjusted to 4, it is very slow! ! The link to the original version is given below

AI backgammon (original version)

So I improved it, because a normal person playing backgammon will not play a chess in the east and a chess in the west.
Therefore, we can greatly narrow the scope of the search, just search around the chess pieces that have been played (2×2 or 3×3).
The following program will be 2×2 by 4, and while still a bit slower, it is much faster than the original program.

In addition, regarding the man-machine strength and man-machine time-consuming modification, I put it in the link of the original version

We can make a comparison: Let these two programs run at the same time 4, you will find that: the improved program took 1:17 to go to the next step, but the original version took 3:04 (4GB memory, i3cpu case)

#include<iostream>
#include<vector>
#include<array>
#include<fstream>
#include<algorithm>
#include <bits/stdc++.h>
#include <windows.h>
using namespace std;
int minx=14,miny=14,maxx=0,maxy=0;
void color(int x) {
    
    
	switch(x) {
    
    
		case  1:
			SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY |FOREGROUND_RED  );
			break;
		case  2:
			SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY |FOREGROUND_BLUE );
			break;
		case  3:
			SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY |FOREGROUND_GREEN);
			break;
		case  4:
			SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY |FOREGROUND_RED  |FOREGROUND_BLUE );
			break;
		case  5:
			SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY |FOREGROUND_RED  |FOREGROUND_GREEN);
			break;
		case  6:
			SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY |FOREGROUND_BLUE |FOREGROUND_GREEN);
			break;
		case  7:
			SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY |FOREGROUND_GREEN|FOREGROUND_BLUE |FOREGROUND_RED);
			break;
		default:
			SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY |FOREGROUND_GREEN|FOREGROUND_BLUE |FOREGROUND_RED);
			break;
	}
}
class GameTree {
    
    
	public:
		class Node {
    
    
			public:
				enum State :uint8_t/*节省内存*/ {
    
     SPACE, BLACK, WHITE };
			private:
				friend class GameTree;
				static const uint8_t BOARDSIZE = 15;
				int value;//叶节点表示估价函数的结果,MAX节点表示α值,MIN节点表示β值
				int evaluateValue;//估价函数计算的结果,用于优化
				unsigned short depth;//深度
				uint8_t lastX, lastY;//上一次落子的xy坐标
				Node* father;//父亲节点
				std::vector<Node*> children;//子节点
				State **board;//棋盘
				int Evaluate()const {
    
     //估价函数
					static const auto EvaluateSome = [](State **board, uint8_t beginX, uint8_t endX, uint8_t beginY, uint8_t endY) {
    
    
						static const auto EvaluateList = [](const std::array<State, 5>& v) {
    
     //假定自己是白方
							//判断颜色并记录棋子个数
							State lastColor = SPACE;
							uint8_t bitList = 0;//将棋链以二进制形式表示,如01101
							for (State i : v) {
    
    
								if (i != lastColor) {
    
    
									if (lastColor == SPACE)//遇到的第一个棋子
										lastColor = i;
									else//有不同颜色的棋子
										return 0;
								}
								if (i != SPACE)
									bitList = bitList * 2 + 1;
							}
							int result = 0;
							switch (bitList) {
    
    
								case 0://00000
									result = 0;
									break;
								case 1://00001
								case 2://00010
								case 4://00100
								case 8://01000
								case 16://10000
									result = 5;
									break;
								case 3://00011
								case 24://11000
									result = 80;
									break;
								case 6://00110
								case 12://01100
									result = 100;
									break;
								case 10://01010
									result = 80;
									break;
								case 5://00101
								case 20://10100
									result = 60;
									break;
								case 9://01001
								case 18://10010
									result = 20;
									break;
								case 17://10001
									result = 10;
									break;
								case 7://00111
								case 28://11100
									result = 800;
									break;
								case 14://01110
									result = 1000;
									break;
								case 13://01101
								case 26://11010
								case 11://01011
								case 22://10110
									result = 800;
									break;
								case 19://10011
								case 21://10101
								case 25://11001
									result = 600;
									break;
								case 15://01111
								case 30://11110
									result = 10000;
									break;
								case 29://11101
								case 23://10111
									result = 8000;
									break;
								case 27://11011
									result = 6000;
									break;
								case 31://11111
									return lastColor == WHITE ? INT_MAX : INT_MIN;
							}
							return lastColor == WHITE ? result : -result;//对手返回负值,我方返回正值
						};
						int result = 0;
						for (uint8_t i = beginX; i < endX; i++) {
    
     //分别从四个方向判断
							for (uint8_t j = beginY; j < endY; j++) {
    
    
								if (j + 4 < endY) {
    
    
									std::array<State, 5>v;
									for (uint8_t k = 0; k < 5; k++)
										v[k] = board[i][j + k];
									const int t = EvaluateList(v);
									if (t == INT_MAX || t == INT_MIN)//决出胜负直接返回
										return t;
									result += t;
								}
								if (i + 4 < endX) {
    
    
									std::array<State, 5>v;
									for (uint8_t k = 0; k < 5; k++)
										v[k] = board[i + k][j];
									const int t = EvaluateList(v);
									if (t == INT_MAX || t == INT_MIN)//决出胜负直接返回
										return t;
									result += t;
								}
								if (i + 4 < endX && j + 4 < endY) {
    
    
									std::array<State, 5>v;
									for (uint8_t k = 0; k < 5; k++)
										v[k] = board[i + k][j + k];
									const int t = EvaluateList(v);
									if (t == INT_MAX || t == INT_MIN)//决出胜负直接返回
										return t;
									result += t;
								}
								if (i + 4 < endX && j >= 4) {
    
    
									std::array<State, 5>v;
									for (uint8_t k = 0; k < 5; k++)
										v[k] = board[i + k][j - k];
									const int t = EvaluateList(v);
									if (t == INT_MAX || t == INT_MIN)//决出胜负直接返回
										return t;
									result += t;
								}
							}
						}
						return result;
					};
					uint8_t beginX, endX, beginY, endY;
					if (lastX <= 5)
						beginX = 0;
					else
						beginX = lastX - 5;
					endX = lastX + 5;
					if (endX > BOARDSIZE)
						endX = BOARDSIZE;
					if (lastY <= 5)
						beginY = 0;
					else
						beginY = lastY - 5;
					endY = lastY + 5;
					if (endY > BOARDSIZE)
						endY = BOARDSIZE;
					const int t = EvaluateSome(board, beginX, endX, beginY, endY);
					if (t == INT_MAX || t == INT_MIN)//决出胜负直接返回
						return t;
					return  t - EvaluateSome(father->board, beginX, endX, beginY, endY) + father->evaluateValue;
				}

			public:
				//非根节点的构造函数
				Node(Node* nf, uint8_t x, uint8_t y) :father(nf), lastX(x), lastY(y), depth(nf->depth + 1), value(0), board(new State* [BOARDSIZE]) {
    
    
					father->children.push_back(this);
					for (int i = 0; i < BOARDSIZE; ++i) {
    
    
						board[i] = new State[BOARDSIZE];
						memcpy(board[i], father->board[i], BOARDSIZE * sizeof(State));
					}
					board[lastX][lastY] = IsMaxNode() ? BLACK : WHITE;
					evaluateValue = Evaluate();
					for (int i = 0; i < BOARDSIZE; ++i) {
    
    
						delete[] board[i];
					}
					delete[] board;
					board = nullptr;
				}
				//根节点的构造函数
				Node(int _depth, uint8_t x, uint8_t y) :father(nullptr), depth(_depth), lastX(x), lastY(y), value(0),evaluateValue(0),board(new State*[BOARDSIZE]) {
    
    
					for (int i = 0; i < BOARDSIZE; ++i) {
    
    
						board[i] = new State[BOARDSIZE];
						memset(board[i], 0, BOARDSIZE * sizeof(State));
					}
					board[x][y] = IsMaxNode() ? BLACK : WHITE;
				}
				inline int GetEvaluateValue()const {
    
    
					return evaluateValue;
				}
				inline bool IsMaxNode()const {
    
     //默认计算机后手
					return depth & 1u;//相当于depth%2
				}
				void Search(unsigned short _depth) {
    
    
					if (_depth == 0 || this->evaluateValue == INT_MAX || this->evaluateValue == INT_MIN) {
    
    
						this->value = this->evaluateValue;
						return;
					}
					bool created = false;//记录是否new出新的Node,如果没有就不用排序了。
					if (!board) {
    
     //不是根节点
						board = new State * [BOARDSIZE];
						for (int i = 0; i < BOARDSIZE; ++i) {
    
    
							board[i] = new State[BOARDSIZE];
							memcpy(board[i], father->board[i], BOARDSIZE * sizeof(State));
						}
						board[lastX][lastY] = IsMaxNode() ? BLACK : WHITE;
					}
					for (int i = max(minx-2,0); i < min(maxx+2,14); i++) {
    
    
						for (int j = max(miny-2,0); j < min(maxy+2,14); j++) {
    
    
							if (!board[i][j]) {
    
    
								bool flag = false;
								if (_depth >= 2) {
    
     //若剩余深度小于2,则下一层肯定没有搜索过
									for (Node* child : this->children) {
    
    
										if (child->lastX == i && child->lastY == j) {
    
     //已经被搜索过
											flag = true;
											break;
										}
									}
								}
								if (!flag) {
    
    
									new Node(this, i, j);
									minx=min(minx,i);
									maxx=max(maxx,i);
									miny=min(miny,j);
									maxy=max(maxy,j);
									created = true;
								}
							}
						}
					}
					if (IsMaxNode()) {
    
    
						this->value = INT_MIN;
						if (created) {
    
    
							std::sort(this->children.begin(), this->children.end(), [](Node* a, Node* b) {
    
    
								return a->GetEvaluateValue() > b->GetEvaluateValue();
							});//按照估价从大到小排序,增加剪枝的概率
						}
					} else {
    
    
						this->value = INT_MAX;
						if (created) {
    
    
							std::sort(this->children.begin(), this->children.end(), [](Node* a, Node* b) {
    
    
								return a->GetEvaluateValue() < b->GetEvaluateValue();
							});//按照估价从小到大排序,增加剪枝的概率
						}
					}
					auto ReleaseMemory = [this] {
    
    
						if (father) {
    
     //不是根节点
							for (int i = 0; i < BOARDSIZE; ++i) {
    
    
								delete[] board[i];
							}
							delete[] board;
							board = nullptr;
						}
					};
					for (Node* child : this->children) {
    
    
						child->Search(_depth - 1);
						//α - β 剪枝
						if (IsMaxNode()) {
    
    
							if (child->value > this->value) {
    
    
								this->value = child->value;
								if (this->father && this->value >= this->father->value && this != this->father->children.front()) {
    
    
									ReleaseMemory();
									return;//剪枝
								}
							}
						} else {
    
     //MIN节点
							if (child->value < this->value) {
    
    
								this->value = child->value;
								if (this->father && this->value <= this->father->value && this != this->father->children.front()) {
    
    
									ReleaseMemory();
									return;//剪枝
								}
							}
						}
					}
					ReleaseMemory();
				}
				void DeleteAllButThis() {
    
    
					if (!father->board)//父节点不是根节点
						throw std::invalid_argument("this->father必须是根节点!");
					for (Node* n : father->children) {
    
    
						if (n != this)
							delete n;
					}
					board = new State * [BOARDSIZE];
					for (int i = 0; i < BOARDSIZE; ++i) {
    
    
						board[i] = new State[BOARDSIZE];
						memcpy(board[i], father->board[i], BOARDSIZE * sizeof(State));
						delete[] father->board[i];
					}
					delete[] father->board;
					board[lastX][lastY] = IsMaxNode() ? BLACK : WHITE;
					free(father);//避免调用析构函数
					father = nullptr;
				}
				inline bool IsFull()const {
    
    
					return depth == BOARDSIZE * BOARDSIZE;
				}
				inline State GetWinner()const {
    
    
					if (this->value == INT_MAX) {
    
    
						return Node::WHITE;
					} else if (this->value == INT_MIN) {
    
    
						return Node::BLACK;
					}
					return Node::SPACE;
				}
				~Node() {
    
    
					if (board) {
    
    
						for (int i = 0; i < BOARDSIZE; ++i) {
    
    
							delete[] board[i];
						}
						delete[] board;
					}
					for (Node* n : children) {
    
    
						delete n;
					}
				}
		};
	private:
		Node* root;
		const unsigned short maxDepth;
	public:
		GameTree(unsigned short _maxDepth) : root(nullptr), maxDepth(_maxDepth) {
    
    
			if (_maxDepth < 2)
				throw std::invalid_argument("最大层数必须大于等于2!");
		}
		std::pair<uint8_t, uint8_t>AIGetNextPos(uint8_t x, uint8_t y) {
    
    
			if (root) {
    
    
				for (Node* node : root->children) {
    
     //进入用户选择的分支
					if (node->lastX == x && node->lastY == y) {
    
    
						node->DeleteAllButThis();
						root = node;
						break;
					}
				}
			} else {
    
     //第一次开局
				root = new Node(1, x, y);
			}
			root->Search(maxDepth);
			if (root->IsFull())
				return std::make_pair(19, 19);
			for (Node* node : root->children) {
    
     //选择分值最大的
				if (node->value == root->value) {
    
    
					node->DeleteAllButThis();
					root = node;
					break;
				}
			}
			return std::make_pair(root->lastX, root->lastY);
		}
		Node::State GetWinner()const {
    
    
			return root->GetWinner();
		}
		void Run() {
    
    
			while (1) {
    
    
				int x, y;
				do {
    
    
					color(7);
					std::cout << "输入x,y坐标";
					color(3);
					std::cin >> y >> x;
					y-=1;
					x-=1;
				} while (x < 0 || y < 0 || x >= 15 || y >= 15 || (root && root->board[x][y] != Node::SPACE));
				minx=min(minx,y);
				maxx=max(maxx,y);
				miny=min(miny,x);
				maxy=max(maxy,x);
				if (root) {
    
    
					for (Node* node : root->children) {
    
     //进入用户选择的分支
						if (node->lastX == x && node->lastY == y) {
    
    
							node->DeleteAllButThis();
							root = node;
							break;
						}
					}
				} else {
    
     //第一次开局
					root = new Node(1, x, y);
				}
				system("cls");
				for (int i = 0; i <= 15; i++) {
    
    
					for (int j = 0; j <= 15; j++) {
    
    
						color(6);
						if (i==0 && j<10)
							cout <<" " <<j <<" ";
						else if (i==0 && j>=10)
							cout <<j <<" ";
						else if (j==0 && i<10)
							cout <<" " <<i <<" ";
						else if (j==0 && i>=10)
							cout <<i <<" ";
						else if (root->board[i-1][j-1] == Node::SPACE) {
    
    
							color(5);
							std::cout << "十 ";
						} else if (root->board[i-1][j-1] == Node::BLACK) {
    
    
							color(2);
							std::cout << "○ ";
						} else {
    
    
							color(7);
							std::cout << "○ ";
						}
					}
					std::cout << '\n';
				}
				root->Search(maxDepth);
				if (root->value == INT_MAX) {
    
    
					std::cout << "电脑胜利!";
					break;
				} else if (root->value == INT_MIN) {
    
    
					std::cout << "玩家胜利!";
					break;
				} else if (root->IsFull()) {
    
     //不能用root->value==0判断平局,因为平局一定为0,但为0不一定平局
					std::cout << "平局!";
					break;
				}
				for (Node* node : root->children) {
    
     //选择分值最大的
					if (node->value == root->value) {
    
    
						node->DeleteAllButThis();
						root = node;
						break;
					}
				}
				system("cls");
				for (int i = 0; i <= 15; i++) {
    
    
					for (int j = 0; j <= 15; j++) {
    
    
						color(6);
						if (i==0 && j<10)
							cout <<" " <<j <<" ";
						else if (i==0 && j>=10)
							cout <<j <<" ";
						else if (j==0 && i<10)
							cout <<" " <<i <<" ";
						else if (j==0 && i>=10)
							cout <<i <<" ";
						else if (root->board[i-1][j-1] == Node::SPACE) {
    
    
							color(5);
							std::cout << "十 ";
						} else if (root->board[i-1][j-1] == Node::BLACK) {
    
    
							color(2);
							std::cout << "○ ";
						} else {
    
    
							color(7);
							std::cout << "○ ";
						}
					}
					std::cout << '\n';
				}
				if (root->value == INT_MAX) {
    
    
					std::cout << "电脑胜利!";
					break;
				} else if (root->value == INT_MIN) {
    
    
					std::cout << "玩家胜利!";
					break;
				} else if (root->IsFull()) {
    
     //不能用root->value==0判断平局,因为平局一定为0,但为0不一定平局
					std::cout << "平局!";
					break;
				}
			}
		}
		~GameTree() {
    
    
			delete root;
		}
};
int main() {
    
    
	cout <<"\n\n\n\n\n\n                           ";
	color(6);
	Sleep(1000);
	cout <<"游";
	Sleep(1000);
	cout <<"戏";
	Sleep(1000);
	cout <<"开";
	Sleep(1000);
	cout <<"始";
	Sleep(1000);
	cout <<"!";
	Sleep(2000);
	system("cls");
	for (int i = 0; i <= 15; i++) {
    
    
		for (int j = 0; j <= 15; j++) {
    
    
			color(6);
			if (i==0 && j<10)
				cout <<" " <<j <<" ";
			else if (i==0 && j>=10)
				cout <<j <<" ";
			else if (j==0 && i<10)
				cout <<" " <<i <<" ";
			else if (j==0 && i>=10)
				cout <<i <<" ";
			else {
    
    
				color(5);
				std::cout << "十 ";
			}
		}
		std::cout << '\n';
	}
	GameTree(4).Run();	//较为智能的模式,可改为3、2(不智能模式),以及5(超级智能模式,但是特别慢) 
	return 0; 
}

Guess you like

Origin blog.csdn.net/DUXS11/article/details/132149850
Recommended