运用了极小极大算法,α-β剪枝。运算速度还是很慢,目前最多搜索3层(不加根节点),有待优化。
#pragma once
#include<iostream>
#include<vector>
#include<array>
#include<fstream>
class GameTree
{
private:
class Node
{
public:
static const unsigned short SIZE = 15;
enum State { SPACE, BLACK, WHITE };
int value;
unsigned short depth;
uint8_t lastX, lastY;
Node* father;
std::vector<Node*> children;
State board[SIZE][SIZE];
Node() :father(nullptr), depth(0), value(INT32_MAX),lastX(SIZE),lastY(SIZE)
{
memset(board, 0, sizeof(board));
}
Node(Node* nf, uint8_t x, uint8_t y) :father(nf), lastX(x), lastY(y), depth(nf->depth + 1),value(0)
{
father->children.push_back(this);
memcpy_s(board, sizeof(board), father->board, sizeof(father->board));
if (IsMaxNode())
{
board[x][y] = BLACK;
}
else
{
board[x][y] = WHITE;
}
}
Node(int _depth, uint8_t x, uint8_t y):father(nullptr),depth(_depth),lastX(x),lastY(y),value(0)
{
memset(board, 0, sizeof(board));
if (IsMaxNode())
{
board[x][y] = BLACK;
}
else
{
board[x][y] = WHITE;
}
}
void Search(unsigned short _depth)
{
value = Evaluate();
if (_depth == 0 || value == INT_MAX || value == INT_MIN)
return;
if (IsMaxNode())
value = INT_MIN;
else
value = INT_MAX;
for (uint8_t i = 0; i < SIZE; i++)
{
for (uint8_t j = 0; j < SIZE; j++)
{
if (!board[i][j])
{
Node* node = nullptr;
for (Node* child : children)
{
if (child->lastX == i && child->lastY == j)
{
node = child;
break;
}
}
if (!node)
node = new Node(this, i, j);
node->Search(_depth - 1);
if (IsMaxNode())
{
if (node->value > this->value)
{
this->value = node->value;
if (father && value >= father->value && this != father->children.front())
{
return;
}
}
}
else
{
if (node->value < this->value)
{
this->value = node->value;
if (father && value <= father->value && this != father->children.front())
{
return;
}
}
}
}
}
}
if (children.empty())
{
value = 0;
}
}
bool IsMaxNode()const
{
return depth & 1u;
}
int Evaluate()const
{
int result = 0;
static auto EvaluateSome = [](const std::array<State, 5>& v)
{
State lastColor = SPACE;
uint8_t count = 0;
for (State i : v)
{
if (i != SPACE)
{
++count;
if (i != lastColor)
{
if (lastColor == SPACE)
{
lastColor = i;
}
else
{
return 0;
}
}
}
}
if (!count)
return 0;
if (count == 5)
{
return lastColor == WHITE ? INT_MAX : INT_MIN;
}
const int result = static_cast<int>(std::pow(10, count - 1));
return lastColor == WHITE ? result : static_cast<int>(-1.1 * result);
};
for (uint8_t i = 0; i < 15; i++)
{
for (uint8_t j = 0; j < 15; j++)
{
if (j + 4 < 15)
{
std::array<State, 5>v;
for (uint8_t k = 0; k < 5; k++)
v[k] = board[i][j + k];
const int t = EvaluateSome(v);
if (t == INT_MAX || t == INT_MIN)
return t;
result += t;
}
if (i + 4 < 15)
{
std::array<State, 5>v;
for (uint8_t k = 0; k < 5; k++)
v[k] = board[i + k][j];
const int t = EvaluateSome(v);
if (t == INT_MAX || t == INT_MIN)
return t;
result += t;
}
if (i + 4 < 15 && j + 4 < 15)
{
std::array<State, 5>v;
for (uint8_t k = 0; k < 5; k++)
v[k] = board[i + k][j + k];
const int t = EvaluateSome(v);
if (t == INT_MAX || t == INT_MIN)
return t;
result += t;
}
if (i + 4 < 15 && j - 4 >= 0)
{
std::array<State, 5>v;
for (uint8_t k = 0; k < 5; k++)
v[k] = board[i + k][j - k];
const int t = EvaluateSome(v);
if (t == INT_MAX || t == INT_MIN)
return t;
result += t;
}
}
}
return result;
}
void DeleteAllButThis()
{
for (Node* n : father->children)
{
if (n != this)
delete n;
}
free(father);
father = nullptr;
}
bool IsFull()const
{
for (int i = 0; i < SIZE; i++)
{
for (int j = 0; j < SIZE; j++)
{
if (board[i][j] == SPACE)
return false;
}
}
return true;
}
~Node()
{
for (Node* n : children)
{
delete n;
}
}
};
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);
for (Node* node : root->children)
{
if (node->value == root->value)
{
node->DeleteAllButThis();
root = node;
break;
}
}
return std::make_pair(root->lastX, root->lastY);
}
void Run()
{
while (1)
{
int x, y;
do
{
std::cout << "输入x,y坐标";
std::cin >> x >> y;
} while (x < 0 || y < 0 || x >= 15 || y >= 15 || (root && root->board[x][y] != Node::SPACE));
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 < Node::SIZE; i++)
{
for (int j = 0; j < Node::SIZE; j++)
{
if (root->board[i][j] == Node::SPACE)
std::cout << "十 ";
else if (root->board[i][j] == Node::BLACK)
std::cout << "黑 ";
else
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())
{
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 < Node::SIZE; i++)
{
for (int j = 0; j < Node::SIZE; j++)
{
if (root->board[i][j] == Node::SPACE)
std::cout << "十 ";
else if (root->board[i][j] == Node::BLACK)
std::cout << "黑 ";
else
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())
{
std::cout << "平局!";
break;
}
}
}
~GameTree()
{
delete root;
}
};
|