C/C++中国象棋程序入门与提高
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

3.4 不同表示方法的转换

一维数组与FEN串表示方法是非常重要的两种表示方法,博弈程序内部用到一维数组,与其他博弈程序对弈进行通信时要用到FEN串。博弈程序必须要能够将局面正确的从一维数组转换成FEN串,也要能够将FEN串表示的局面转换成一维数组。

3.4.1 一维数组转换成FEN串

算法3-1:一维数组转换成FEN串

            行变量i=3 to 12
            空格变量k=0
            列变量j=3 to 11
                    pc= 棋盘i行j列元素值
                    if pc==0
                        k++;
                    else
                        if k>0
                            数字k转换成字符后附在字符串的尾部
                            k=0
                        pc值对应的字符附在字符串的尾部
            if k>0
                    数字k转换成字符后附在字符串的尾部
                    k=0
            if i!=12
                    附加’/’在字符串尾部
            附加空格在字符串尾部
            if是红方走棋
                    ‘w’附加在字符串尾部
            else
                    ‘b’附加在字符串尾部
            在字符串尾部增加结束符号’\0’

程序代码

          // 将一维数组表示的局面转换成FEN串
          //---------------变量声明----------------------------------------------
              int side;                    // 轮到哪方走,0表示红方,1表示黑方
              unsigned char board[256];   // 棋盘数组
              char FenString[128];     //局面的FEN串格式
              void ArrayToString()
              {
                int i, j, k, pc;
                char *str;
                str = FenString;
                for (i = 3; i <= 12; i ++)
                {
                    k = 0;
                    for (j = 3; j <= 11; j ++)
                    {
                        pc = board[(i << 4) + j];
                        if (pc != 0)
                        {
                            if (k > 0)
                            {
                                *str = k + '0';
                                str ++;
                                k = 0;
                            }
                            *str = IntToChar(pc);
                            str ++;
                        }
                        else
                        {
                            k ++;
                        }
                    }
                    if (k > 0)
                    {
                        *str = k + '0';
                        str ++;
                    }
                    *str = '/';
                    str ++;
              }
              str --;
              *str = ' ';
              str ++;
              *str = (side == 0 ? 'w' : 'b');
              str ++;
              *str = '\0';
          }

代码技巧

数字k转换成字符:char ch = ‘0’ + k

二维矩阵i行j列位置转换成一维数组位置:(i << 4) + j

pc值对应的字符:如何求得pc整数对应的字符,可以用一个函数来实现

          char IntToChar(int a)
          {
              if(a <32)
              {
                switch(a)
                {
                case 16:    return 'K';
                case 17:
                case 18:    return 'A';
                case 19:
                case 20:    return 'B';
                case 21:
                case 22:    return 'N';
                case 23:
                case 24:    return 'R';
                case 25:
                case 26:    return 'C';
                case 27:
                case 28:
                case 29:
                case 30:
                case 31:    return 'P';
                default:    return 0;
                }
              }
              else
              {
                a = a-16;
                switch(a)
                {
                case 16:    return 'k';
                case 17:
                case 18:    return 'a';
                case 19:
                case 20:    return 'b';
                case 21:
                case 22:    return 'n';
                case 23:
                case 24:    return 'r';
                case 25:
                case 26:    return 'c';
                case 27:
                case 28:
                case 29:
                case 30:
                case 31:    return 'p';
                default:    return 0;
                }
              }
          }

3.4.2 FEN串转换成一维数组

算法3-2:FEN串转换成一维数组

        清空一维数组棋盘
        行变量i=3
        列变量j=3
        str= 字符串下一字符
        while(str!=’ ‘)
            if (str == '/')
                换行操作:j = 3;i ++;
            else if str>=’1’ && str<=’9’
                列变量j向后移动str个位置j= j+(str-‘0’)
            else if str>=’A’ && str<=’Z’
                将字符转换成红方棋子的整数表示
                将整数放入数组相应位置i<<4+j
            else if str>=’a’ && str<=’z’
                将字符转换成黑方棋子的整数表示
                将整数放入数组相应位置i<<4+j
            str= 字符串下一字符
        str= 字符串下一字符
        //判断哪方走棋
        if(str!=’b’)
            side =0;
        else
            side =1;

程序代码

          void ClearBoard() //清空棋盘数组
          {
              int i;
              side = 0;
              for (i = 0; i < 256; i ++)
              {
                board[i] = 0;
              }
          }
          void StringToArray(const char *FenStr) //将FEN串表示的局面转换成一维数组
          {
              int i, j, k;
              int pcWhite[7]={16,17,19,21,23,25,27};
              int pcBlack[7]={32,33,35,37,39,41,43};
              const char *str;
              ClearBoard();
              str = FenStr;
              if (*str == '\0')
              {
                return;
              }
              i = 3;
              j = 3;
              while (*str != ' ')
              {
                if (*str == '/')
                {
                    j = 3;
                    i ++;
                    if (i > 12)
                    {
                        break;
                    }
                }
                else if (*str >= '1' && *str <= '9')
                {
                    for (k = 0; k < (*str - '0'); k ++)
                    {
                        if (j >= 11)
                        {
                            break;
                        }
                        j ++;
                    }
                }
                else if (*str >= 'A' && *str <= 'Z')
                {
                    if (j <= 11)
                    {
                        k = CharToSubscript(*str);
                        if (k < 7)
                        {
                            if (pcWhite[k] < 32)
                            {
                                board[(i<<4) + j] = pcWhite[k];
                                pcWhite[k]++;
                            }
                        }
                        j ++;
                    }
                }
                else if (*str >= 'a' && *str <= 'z')
                {
                    if (j <= 11)
                    {
                        k = CharToSubscript(*str);
                        if (k < 7)
                        {
                            if (pcBlack[k] < 48)
                            {
                                board[(i<<4) + j] = pcBlack[k];
                                pcBlack[k]++;
                            }
                        }
                        j ++;
                    }
                }
                str ++;
                if (*str == '\0')
                {
                    return;
                }
              }
              str ++;
              if (*str == 'b')
                side = 1;
              else
                side = 0;
          }

代码技巧

设置一个数组pcWhite[7],保存每一种红方棋子的初始整数值,如表3-4所示。

表3-4 每一种红方棋子的初始整数值

下标0,1,2,3,4,5,6分别对应表示帅,仕,相,马,车,炮,兵。

当字符串中出现R时,表示红方一个车。如下操作可实现:

          Int j = pcWhite[4]; //第1个车对应整数23
          pcWhite[4]++;//将不同的车对应到不同的值,下一个车则是24

那又如何得到车的下标是4呢?

          int CharToSubscript(char ch)
          {
              switch(ch)
              {
              case 'k':
              case 'K':return 0;
              case 'a':
              case 'A':return 1;
              case 'b':
              case 'B':return 2;
              case 'n':
              case 'N':return 3;
              case 'r':
              case 'R':return 4;
              case 'c':
              case 'C':return 5;
              case 'p':
              case 'P':return 6;
              default:return 7;
              }
          }

同理设置一个数组pcBlack[7],保存每一种黑方棋子的初始整数值,如表3-5所示。

表3-5 每一种黑方棋子的初始整数值

下标0,1,2,3,4,5,6分别对应表示将,士,象,马,车,炮,卒。

当字符串中出现R时,表示黑方一个车。如下操作可实现:

          int j = pcWhite[4]; //第1个车对应整数39
          pcWhite[4]++;//将不同的车对应到不同的值,下一个车则是40

参见程序:3-1.cpp