diff --git a/.gitignore b/.gitignore index 7d29a7ebd2b122207e07eba34bc228429b7e4c95..35530cf67b23b9d4022beaf1c48648c0e399e1fd 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,5 @@ release *.pdb build-* *.user -*.exe \ No newline at end of file +*.exe +.vscode diff --git a/chesspi/chesspi.h b/chesspi/chesspi.h new file mode 100644 index 0000000000000000000000000000000000000000..b891152e5e7778f375825e1d36edfec5270c205d --- /dev/null +++ b/chesspi/chesspi.h @@ -0,0 +1,61 @@ +#ifndef CHESSPI_H +#define CHESSPI_H +#include +#include +/** + * @brief The chess_node struct 棋盘状态节点 + */ +struct chess_node{ + /** + * @brief coords 棋盘坐标, + * 每个字节一个棋子,X(高4比特)Y(低4比特),X1-9,Y1-10 + * 顺序:0=红方, 1=黑方 + * 0 15 16 31 + * 帅士士相相马马车车炮炮兵兵兵兵兵 將仕仕象象馬馬車車砲砲卒卒卒卒卒 + */ + unsigned char coords[32]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + /*! + * \brief alive 存活标记,每个1比特.顺序:0=红方, 1=黑方 + * 0 15 16 31 + * 帅士士相相马马车车炮炮兵兵兵兵兵 將仕仕象象馬馬車車砲砲卒卒卒卒卒 + */ + unsigned int alive = 0; + size_t parent = 0; + size_t leaves = 0; + float jump_cost[2]{0,0};//跳转损失 + char side = 0; + char depth = 0; + //遍历 + float weight = 1; +}; + + +//走位和显示 +//------------------------------------------- +std::vector expand_node(const chess_node & root, const int side); + +bool move_node(const chess_node & root, chess_node * new_node,const int oldx, const int oldy,const int newx, const int newy,const int side); + + +bool build_node(const int coordx[/*32*/], const int coordy[/*32*/],const int alive[/*32*/],const int idx, const int newx, const int newy,const int side,int map_coords[/*11*/][10],chess_node * node); + +bool build_node(const int coordx[/*32*/], const int coordy[/*32*/],const int alive[/*32*/],const int side,chess_node * node); + +void print_node(const chess_node & node); + +void mirror_coordx(const unsigned char cod1[/*32*/],unsigned char cod2[/*32*/]); + +std::vector node2hash(const std::vector & nodes); + +std::string node2hash(const unsigned char cod[/*32*/], const unsigned int alive); + + +//AI +//------------------------------------------- +unsigned int calc_cost(const int coordx[/*32*/], const int coordy[/*32*/],const int idx); + +std::vector build_tree(const chess_node & root, const int side,const std::vector & history); + +size_t judge_tree(std::vector & tree); + +#endif // CHESSPI_H diff --git a/chesspi/chesspi.pro b/chesspi/chesspi.pro new file mode 100644 index 0000000000000000000000000000000000000000..826d536b4578e9e037d0e9b64ec2bfc16d3c6182 --- /dev/null +++ b/chesspi/chesspi.pro @@ -0,0 +1,15 @@ +TEMPLATE = app +CONFIG += console +CONFIG -= app_bundle +CONFIG -= qt + +SOURCES += \ + main.cpp \ + chesspi_rules.cpp \ + chesspi_ai.cpp + +HEADERS += \ + chesspi.h + +QMAKE_CXXFLAGS += -fopenmp +LIBS += -lgomp diff --git a/chesspi/chesspi_ai.cpp b/chesspi/chesspi_ai.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6df2b1f2bd30a84226c579a0d7113646b808e91c --- /dev/null +++ b/chesspi/chesspi_ai.cpp @@ -0,0 +1,138 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "chesspi.h" + +unsigned int calc_cost(const int coordx[/*32*/], const int coordy[/*32*/],const int idx) +{ + unsigned int cost[16] = {100000,150,150,150,150,100,100,100,100,500,500,10,100,1000,100,10}; + + assert(idx >= 16); + + unsigned int rescost = cost[idx%16]; + + return rescost; +} + +std::vector build_tree(const chess_node & root, const int side,const std::vector & history) +{ + std::vector tree; + std::unordered_set dict; + for (const chess_node & n: history) + dict.insert(node2hash(n.coords,n.alive)); + tree.push_back(root); + tree[0].side = side % 2; + tree[0].depth = 0; + + size_t curr_i = 0; + size_t max_nodes = 1024*1024*4; + while (tree.size()<=max_nodes && curr_i > vec_appends; + for (int i=0;i()); + std::atomic new_appends (0); +#pragma omp parallel for + for (int i=curr_i;i=max_nodes) + continue; + const unsigned char clock = tree[i].depth; + const int tid = omp_get_thread_num(); + if ((tree[i].alive & 0x00010001)==0x00010001) + { + const int curr_side = (side + clock) % 2; + std::vector next_status = + expand_node(tree[i],curr_side); + + const size_t sz = next_status.size(); + for (size_t j=0;jdepth); + + return tree; +} + +size_t judge_tree(std::vector & tree) +{ + const size_t total_nodes = tree.size(); + if (total_nodes<2) + return 0; + int side = tree[0].side; + size_t i = total_nodes - 1; + while (i > 0) + { + if (tree[i].side==0) + { + float ratio = sqrt((tree[i].jump_cost[1]+1) / (tree[i].jump_cost[0]+1)/ (tree[i].jump_cost[0]+1)); + tree[i].weight = ratio; + } + else + { + float ratio = sqrt((tree[i].jump_cost[0]+1) / (tree[i].jump_cost[1]+1)/ (tree[i].jump_cost[1]+1)); + tree[i].weight = ratio; + } + size_t parent = tree[i].parent; + tree[parent].jump_cost[0] += tree[i].jump_cost[0] * tree[i].weight/tree[i].depth/tree[i].depth; + tree[parent].jump_cost[1] += tree[i].jump_cost[1] * tree[i].weight/tree[i].depth/tree[i].depth; + --i; + } + + size_t p = 1; + float max_v = 0; + int max_p = 1; + while (p max_v) + { + max_v = v; + max_p = p; + } + ++p; + } + return max_p; +} diff --git a/chesspi/chesspi_rules.cpp b/chesspi/chesspi_rules.cpp new file mode 100644 index 0000000000000000000000000000000000000000..efd2782bcb24576a3afe6fdfd9523d8e39526f9e --- /dev/null +++ b/chesspi/chesspi_rules.cpp @@ -0,0 +1,515 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "chesspi.h" + + +std::vector expand_node(const chess_node & r_root, const int side) +{ + const chess_node * root = &r_root; + static const int valid_directs[16] = {4,4,4,4,4,8,8,4,4,4,4,3,3,3,3,3}; + static const int valid_coords[16][8][2] = { + {{-1,0},{1,0},{0,-1},{0,1},{100,100},{100,100},{100,100},{100,100}}, + {{-1,-1},{1,1},{1,-1},{-1,1},{100,100},{100,100},{100,100},{100,100}}, + {{-1,-1},{1,1},{1,-1},{-1,1},{100,100},{100,100},{100,100},{100,100}}, + {{-2,-2},{2,2},{2,-2},{-2,2},{100,100},{100,100},{100,100},{100,100}}, + {{-2,-2},{2,2},{2,-2},{-2,2},{100,100},{100,100},{100,100},{100,100}}, + {{-1,-2},{1,2},{1,-2},{-1,2},{-2,-1},{2,1},{2,-1},{-2,1}}, + {{-1,-2},{1,2},{1,-2},{-1,2},{-2,-1},{2,1},{2,-1},{-2,1}}, + {{-1,0},{1,0},{0,-1},{0,1},{100,100},{100,100},{100,100},{100,100}}, + {{-1,0},{1,0},{0,-1},{0,1},{100,100},{100,100},{100,100},{100,100}}, + {{-1,0},{1,0},{0,-1},{0,1},{100,100},{100,100},{100,100},{100,100}}, + {{-1,0},{1,0},{0,-1},{0,1},{100,100},{100,100},{100,100},{100,100}}, + {{0,1},{1,0},{-1,0},{100,100},{100,100},{100,100},{100,100},{100,100}}, + {{0,1},{1,0},{-1,0},{100,100},{100,100},{100,100},{100,100},{100,100}}, + {{0,1},{1,0},{-1,0},{100,100},{100,100},{100,100},{100,100},{100,100}}, + {{0,1},{1,0},{-1,0},{100,100},{100,100},{100,100},{100,100},{100,100}}, + {{0,1},{1,0},{-1,0},{100,100},{100,100},{100,100},{100,100},{100,100}} + }; + std::vector res; + //如果是黑方,反转坐标 + int coordx[32]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + int coordy[32]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + int alive[32]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + + if (side==0) + { + for (int i=0;i<32;++i) + { + coordx[i] = root->coords[i] >> 4; + coordy[i] = root->coords[i] & 0x0f; + alive[i] = (root->alive & (1<coords[od] >> 4; + const unsigned char y = root->coords[od] & 0x0f; + coordx[i] = 10 - x; + coordy[i] = 11 - y; + alive[i] = (root->alive & (1<6 || new_y <1 || new_y >3 ) + continue; + chess_node node; + if (!build_node(coordx,coordy,alive,i,new_x,new_y, + side,map_coords,&node)) + continue; + res.push_back(node); + } + if (coordx[0]==coordx[16]) + { + bool hit = true; + for (int cy = coordy[0]+1; cy < coordy[16] && hit;++cy) + if (map_coords[cy][coordx[0]]) + hit = false; + if (hit) + { + chess_node node; + if (!build_node(coordx,coordy,alive,i,coordx[16],coordy[16], + side,map_coords,&node)) + continue; + res.push_back(node); + } + } + + break; + case 1://士 + case 2://士 + for (int d = 0; d < valid_directs[i];++d) + { + const int new_x = coordx[i] + valid_coords[i][d][0]; + const int new_y = coordy[i] + valid_coords[i][d][1]; + if (new_x <4 || new_x >6 || new_y <1 || new_y >3 ) + continue; + chess_node node; + if (!build_node(coordx,coordy,alive,i,new_x,new_y, + side,map_coords,&node)) + continue; + res.push_back(node); + } + break; + case 3://相 + case 4://相 + for (int d = 0; d < valid_directs[i];++d) + { + const int new_x = coordx[i] + valid_coords[i][d][0]; + const int new_y = coordy[i] + valid_coords[i][d][1]; + const int test_x = coordx[i] + valid_coords[i][d][0]/2; + const int test_y = coordy[i] + valid_coords[i][d][1]/2; + if (new_x <1 || new_x >9 || new_y <1 || new_y >5 ) + continue; + if (map_coords[test_y][test_x]) + continue; + chess_node node; + if (!build_node(coordx,coordy,alive,i,new_x,new_y, + side,map_coords,&node)) + continue; + res.push_back(node); + } + break; + case 5://马 + case 6://马 + for (int d = 0; d < valid_directs[i];++d) + { + const int new_x = coordx[i] + valid_coords[i][d][0]; + const int new_y = coordy[i] + valid_coords[i][d][1]; + const int test_x = coordx[i] + valid_coords[i][d][0]/2; + const int test_y = coordy[i] + valid_coords[i][d][1]/2; + if (new_x <1 || new_x >9 || new_y <1 || new_y >10 ) + continue; + if (map_coords[test_y][test_x]) + continue; + chess_node node; + if (!build_node(coordx,coordy,alive,i,new_x,new_y, + side,map_coords,&node)) + continue; + res.push_back(node); + } + break; + case 7://车 + case 8://车 + for (int d = 0; d < valid_directs[i];++d) + { + for (int a=1;a<10;++a) + { + const int new_x = coordx[i] + valid_coords[i][d][0]*a; + const int new_y = coordy[i] + valid_coords[i][d][1]*a; + if (new_x <1 || new_x >9 || new_y <1 || new_y >10 ) + continue; + if (map_coords[new_y][new_x]>0 && map_coords[new_y][new_x]<=16) + break; + chess_node node; + if (!build_node(coordx,coordy,alive,i,new_x,new_y, + side,map_coords,&node)) + continue; + res.push_back(node); + if (map_coords[new_y][new_x]) + break; + } + + } + break; + case 9://炮 + case 10://炮 + for (int d = 0; d < valid_directs[i];++d) + { + int hitn = 0; + for (int a=1;a<10;++a) + { + const int new_x = coordx[i] + valid_coords[i][d][0]*a; + const int new_y = coordy[i] + valid_coords[i][d][1]*a; + if (new_x <1 || new_x >9 || new_y <1 || new_y >10 ) + continue; + if (map_coords[new_y][new_x]) + ++hitn; + if (hitn==0 || hitn==2) + { + chess_node node; + if (!build_node(coordx,coordy,alive,i,new_x,new_y, + side,map_coords,&node)) + break; + res.push_back(node); + } + if (hitn==2) + break; + } + + } + break; + case 11://卒 + case 12://卒 + case 13://卒 + case 14://卒 + case 15://卒 + for (int d = 0; d < valid_directs[i];++d) + { + //小卒不过河只能前进 + if (coordy[i]<6 && d) + break; + const int new_x = coordx[i] + valid_coords[i][d][0]; + const int new_y = coordy[i] + valid_coords[i][d][1]; + if (new_x <1 || new_x >9 || new_y <1 || new_y >10 ) + continue; + chess_node node; + if (!build_node(coordx,coordy,alive,i,new_x,new_y, + side,map_coords,&node)) + continue; + res.push_back(node); + } + break; + default: + assert(false); + break; + } + } + + return res; +} + +bool build_node(const int old_coordx[/*32*/], const int old_coordy[/*32*/], +const int old_alive[/*32*/], +const int idx, const int new_x, const int new_y,const int side, +int map_coords[/*11*/][10], +chess_node * node) +{ + //不能吃自己的棋子 + if (map_coords[new_y][new_x]>=1 && map_coords[new_y][new_x]<=16) + return false; + assert(new_x>0 && new_x <10); + assert(new_y>0 && new_y <11); + int coordx[32]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + int coordy[32]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + int alive[32]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + memcpy(coordx,old_coordx,sizeof(coordx)); + memcpy(coordy,old_coordy,sizeof(coordy)); + memcpy(alive,old_alive,sizeof(alive)); + + coordx[idx] = new_x; + coordy[idx] = new_y; + if (map_coords[new_y][new_x]>16) + { + assert(map_coords[new_y][new_x]); + alive[map_coords[new_y][new_x]-1] = 0; + //计算吃子代价 + node->jump_cost[1-side] = calc_cost(coordx,coordy,map_coords[new_y][new_x]-1); + } + + //反转 + if (side==0) + { + for (int i=0;i<32;++i) + { + node->coords[i] &=0x0f; + node->coords[i] ^= (coordx[i] << 4); + node->coords[i] &=0xf0; + node->coords[i] ^= coordy[i]; + + node->alive |= (1<alive ^= (!alive[i])? (1<coords[i] &=0x0f; + node->coords[i] ^=((10-coordx[od]) << 4); + node->coords[i] &=0xf0; + node->coords[i] ^=11 - coordy[od]; + + node->alive |= (1<alive ^= (!alive[od])? (1<coords[i] &=0x0f; + node->coords[i] ^= (coordx[i] << 4); + node->coords[i] &=0xf0; + node->coords[i] ^= coordy[i]; + + node->alive |= (1<alive ^= (!alive[i])? (1<coords[i] &=0x0f; + node->coords[i] ^= (10 - coordx[od]) << 4; + node->coords[i] &=0xf0; + node->coords[i] ^= 11 - coordy[od]; + + node->alive |= (1<alive ^= (!alive[od])? (1<> 4; + coordy[i] = node.coords[i] & 0x0f; + alive[i] = (node.alive & (1<>4); + printf ("%X",((unsigned char)(nhash[i]))&0x0F); + } + printf ("\n"); + //制作坐标站位表 + int map_coords[11][10]; + memset (map_coords,0,sizeof(map_coords)); + for (int i=0;i<32;++i) + if (alive[i]) + map_coords[coordy[i]][coordx[i]] = i+1; + + if (side) + { + printf (" "); + for (int x = 1; x<=9; ++x) + printf("%2d",x-1); + printf ("\n"); + for (int y = 1; y <=10 ;++y) + { + printf ("%2d ", y-1); + for (int x=1;x<=9;++x) + { + if (map_coords[y][x]>0 && map_coords[y][x]<=16) + printf("\33[1m\033[31m%s\033[0m",pstr[map_coords[y][x]-1]); + else if (map_coords[y][x]>16) + printf("\33[1m\033[36m%s\033[0m",pstr[map_coords[y][x]-1]); + else + printf (" "); + } + printf ("\n"); + } + } + else + { + printf (" "); + for (int x = 1; x<=9; ++x) + printf("%2d",8-(x-1)); + printf ("\n"); + for (int y = 10; y >0 ;--y) + { + printf ("%2d ", y-1); + for (int x=9;x>0;--x) + { + if (map_coords[y][x]>0 && map_coords[y][x]<=16) + printf("\33[1m\033[31m%s\033[0m",pstr[map_coords[y][x]-1]); + else if (map_coords[y][x]>16) + printf("\33[1m\033[36m%s\033[0m",pstr[map_coords[y][x]-1]); + else + printf (" "); + } + printf ("\n"); + } + } + printf ("----------------------------------------\n"); + +} + +std::vector node2hash(const std::vector & nodes) +{ + std::vector v; + const size_t sz = nodes.size(); + for (size_t i=0;i()); + std::sort(str1.begin()+3,str1.begin()+5,std::less()); + std::sort(str1.begin()+5,str1.begin()+7,std::less()); + std::sort(str1.begin()+7,str1.begin()+9,std::less()); + std::sort(str1.begin()+9,str1.begin()+11,std::less()); + std::sort(str1.begin()+11,str1.begin()+16,std::less()); + + std::sort(str1.begin()+17,str1.begin()+19,std::less()); + std::sort(str1.begin()+19,str1.begin()+21,std::less()); + std::sort(str1.begin()+21,str1.begin()+23,std::less()); + std::sort(str1.begin()+23,str1.begin()+25,std::less()); + std::sort(str1.begin()+25,str1.begin()+27,std::less()); + std::sort(str1.begin()+27,str1.begin()+32,std::less()); + + unsigned char codsm[32]; + mirror_coordx(coords,codsm); + + std::string str2; + for (int i=0;i<32;++i) + { + if(alive & (1<()); + std::sort(str2.begin()+3,str2.begin()+5,std::less()); + std::sort(str2.begin()+5,str2.begin()+7,std::less()); + std::sort(str2.begin()+7,str2.begin()+9,std::less()); + std::sort(str2.begin()+9,str2.begin()+11,std::less()); + std::sort(str2.begin()+11,str2.begin()+16,std::less()); + + std::sort(str2.begin()+17,str2.begin()+19,std::less()); + std::sort(str2.begin()+19,str2.begin()+21,std::less()); + std::sort(str2.begin()+21,str2.begin()+23,std::less()); + std::sort(str2.begin()+23,str2.begin()+25,std::less()); + std::sort(str2.begin()+25,str2.begin()+27,std::less()); + std::sort(str2.begin()+27,str2.begin()+32,std::less()); + + if (str1 > str2) + res = str2 + str1; + else + res = str1 + str2; + + return res; +} + +void mirror_coordx(const unsigned char cod1[/*32*/],unsigned char cod2[/*32*/]) +{ + for (int i=0;i<32;++i) + { + const unsigned char x = 10-(cod1[i]>>4); + const unsigned char y = cod1[i] & 0x0f; + cod2[i] = (x<<4) ^ y; + } +} + +bool move_node(const chess_node & root, chess_node * new_node, const int x1, const int y1,const int x2, const int y2,const int side) +{ + std::vector vec = expand_node(root,side); + int idx = -1; + for (int i=0;i<32 && idx < 0;++i) + { + int rx = root.coords[i]>>4; + int ry = root.coords[i]& 0x0F; + if (rx==x1 && ry==y1 && (root.alive & (1<=16) + return false; + if (side==1 && idx <16) + return false; + const size_t sz = vec.size(); + + for (size_t i=0;i> 4; + const int newy = vec[i].coords[idx] & 0x0F; + if (newx == x2 && newy==y2) + { + *new_node = vec[i]; + return true; + } + } + return false; +} diff --git a/chesspi/main.cpp b/chesspi/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2f8ee8e7676d6c0f9892d034aededc27ef115d30 --- /dev/null +++ b/chesspi/main.cpp @@ -0,0 +1,83 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "chesspi.h" + +int main() +{ + //初始棋局 + int coordx[32]{5,4,6,3,7,2,8,1,9,2,8,1,3,5,7,9,5,4,6,3,7,2,8,1,9,2,8,1,3,5,7,9}; + int coordy[32]{1,1,1,1,1,1,1,1,1,3,3,4,4,4,4,4,10,10,10,10,10,10,10,10,10,8,8,7,7,7,7,7}; + int alive[32]{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; + + chess_node root; + + if (!build_node(coordx,coordy,alive,0,&root)) + { + printf ("创建棋局失败!\n"); + return 0; + } + + //回合 + size_t round = 0; + bool finished = false; + print_node(root); + std::vector history; + history.push_back(root); + while (!finished) + { + printf ("\nround %d:\n==========\n", round); + if (round % 2==0) + { + //找到棋子 + bool ok = false; + chess_node new_node; + while (!ok) + { + printf ("请输入四个整数,分别是棋子X,Y,目的X,Y,逗号分割:\n"); + int x1,y1,x2,y2; + scanf("%d,%d,%d,%d",&x1,&y1,&x2,&y2); + ok = move_node(root,&new_node,x1+1,y1+1,x2+1,y2+1,round % 2); + if (!ok) + { + printf ("没有选中棋子.\n"); + getchar(); + } + else { + root = new_node; + + } + } + } + else { + std::vector tree = + build_tree(root,(0+round)%2,history); + size_t best = judge_tree(tree); + if (best <1 || best + 1 > tree.size()) + break; + root = tree[best]; + printf ("Best % d Cost: %f, %f, Weight %f\n",best + ,root.jump_cost[0],root.jump_cost[1],root.weight + ); + } + root.side = 0; + print_node(root); + history.push_back(root); + ++round; + if (!((root.alive & 0x00010001)==0x00010001)) + break; + + + } + printf ("FINISHED!\n"); + + return 0; +} + +