Exemple #1
0
        /// <summary>
        /// 在棋盘内查找三个兵或卒出现在同一列时的列号
        /// 在纵列表示法中会出现“中兵平二”这样的记录
        /// 要全盘查找哪一列上有3个兵,才可以准确定位这个兵
        /// </summary>
        /// <param name="board"></param>
        /// <param name="piece"></param>
        /// <returns>找到3兵或卒在同一列时,返回0-8的列号;否则,返回-1</returns>
        public static int Find3PawnFileNum(Board board, int piece)
        {
            // 这里用了一个比较懒的办法,全部找一遍,统计每一列上兵的出现个数
            // 哪一列上兵出现的次数最多,就返回哪个列号了
            int countMax = 0;
            int file     = -1;

            for (int i = 0; i < 9; i++)
            {
                int numFound = 0;

                for (int rank = 0; rank < 10; rank++)
                {
                    int pos = BoardUtil.Pos(i, rank);
                    if (board.pieceData[pos] == piece)
                    {
                        numFound++;
                    }

                    if (numFound > countMax)
                    {
                        file     = i;
                        countMax = numFound;
                    }
                }
            }
            return(file);
        }
Exemple #2
0
        /// <summary>
        /// 用字符串表示的着法
        /// </summary>
        /// <param name="strMove">例如:"a2c2"</param>
        /// <returns></returns>
        public static Move CreateMoveFromString(Board board, string strMove)
        {
            int from = BoardUtil.Pos(strMove.Substring(0, 2));
            int to   = BoardUtil.Pos(strMove.Substring(2, 2));

            return(board.CreateMove(from, to));
        }
Exemple #3
0
 /// <summary>
 /// 根据行号(0-8)、列号(0-9)得到内部的位置编号
 /// </summary>
 /// <param name="file">列号,0-8</param>
 /// <param name="rank">行号,0-9</param>
 /// <returns>返回内部的编号,从0-238,如果不满足条件,则抛出异常</returns>
 public static int Pos(int file, int rank)
 {
     if (file >= 0 && file < 9 && rank >= 0 && rank < 10)
     {
         return(BoardUtil.Pos(rank * 9 + file));
     }
     throw new Exception("行号、列号越界");
 }
        public void MakeMoves(string strMoves)
        {
            string[] s = strMoves.Split(' ');

            foreach (string move in s)
            {
                MakeMove(BoardUtil.CreateMoveFromString(this, move));
            }
        }
Exemple #5
0
 /// <summary>
 /// 在棋盘的某一列上查找某个棋子的准确位置,从上边(黑方)到下边(红方)的方向搜索
 /// </summary>
 /// <param name="board">棋盘</param>
 /// <param name="piece">棋子编号</param>
 /// <param name="file">列号</param>
 /// <returns>返回找到的棋子位置的编号,找不到时返回0</returns>
 public static int FindPositionFromBlackToRed(Board board, int piece, int file)
 {
     for (int rank = 0; rank <= 9; rank++)
     {
         int pos = BoardUtil.Pos(file, rank);
         if (board.pieceData[pos] == piece)
         {
             return(pos);
         }
     }
     return(0);
 }
Exemple #6
0
 /// <summary>
 /// 在棋盘的某一列上查找某个棋子的准确位置,从下边(红方)到上边(黑方)搜索
 /// </summary>
 /// <param name="board">棋盘</param>
 /// <param name="piece">棋子编号</param>
 /// <returns>返回找到的棋子位置的编号,找不到时返回0</returns>
 public static int FindPositionFromRedToBlack(Board board, int piece)
 {
     for (int file = 0; file <= 8; file++)
     {
         for (int rank = 9; rank >= 0; rank--)
         {
             int pos = BoardUtil.Pos(file, rank);
             if (board.pieceData[pos] == piece)
             {
                 return(pos);
             }
         }
     }
     return(0);
 }
Exemple #7
0
        /// <summary>
        /// 根据FEN字符串初始化棋盘
        /// http://chessprogramming.wikispaces.com/Forsyth-Edwards+Notation
        /// FEN表示法从第9行到第0行扫描棋子,在每一行中,从第0列(第A列)到第8列(第I列)扫描棋子,每一行以字符'/'结束。
        /// 例如:初始状态的FEN字符串是  "rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR w"
        /// 在描述完棋子位置后,根一个空格,然后是一个表示轮到哪方走棋的字符,如果是b,表示轮黑方走棋,r或其它字符都表示红方走棋
        /// </summary>
        /// <param name="fen">FEN格式字符串</param>
        public static void InitFromFEN(Board board, string fen)
        {
            int piece;
            int index = 0;
            int pos90 = 0;

            while (fen[index] != ' ')
            {
                piece = BoardUtil.PieceID(fen[index]);  //把字符转换为棋子的编号;
                if (piece > 0)
                {
                    int pos238 = BoardUtil.Pos(pos90);
                    AddPiece(board, piece, pos238);
                    ++pos90;
                }
                else if (fen[index] >= '1' && fen[index] <= '9')
                {
                    pos90 += fen[index] - '0';        // skip empty squares
                }
                else if (fen[index] != '/')
                {  // if there another char than '/' throw exception
                    // throw new ArgumentException("fen");
                    // 如果程序执行到这里表示FEN字符串有错
                    throw new Exception("Fen代码出错,缺少终止符'/'");
                }

                ++index;
            }

            ++index;

            // 由于国际象棋中是白方先行,这里会记录一个w字母,但在中国象棋中通常会记录r,代表红方
            // 这里把不是b字母的都认为是轮红方走棋
            board.IsRedTurn = (fen[index] != 'b');

            // 最后更新另外几个特殊的位棋盘的状态
            board.TotalRedPiece = board.RedPieceNum[1] + board.RedPieceNum[2] + board.RedPieceNum[3] + board.RedPieceNum[4]
                                  + board.RedPieceNum[5] + board.RedPieceNum[6] + 1; // 最后的1代表红帅
            board.TotalBlackPiece = board.BlackPieceNum[1] + board.BlackPieceNum[2] + board.BlackPieceNum[3] + board.BlackPieceNum[4]
                                    + board.BlackPieceNum[5] + board.BlackPieceNum[6] + 1;
            board.ZobristKey = Zobrist.ZoristHash(board);
        }
Exemple #8
0
        /// <summary>
        /// 为方便调试,用一个简洁的方式来显示棋盘情况
        /// TODO: 不知道是否影响性能
        /// </summary>
        /// <returns>
        /// 盘面字符串
        /// </returns>
        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();

            for (int j = 0; j < 10; j++)
            {
                for (int i = 0; i < 9; i++)
                {
                    int piece = pieceData[BoardUtil.Pos(i, j)];

                    if (piece != 0)
                    {
                        sb.Append(BoardUtil.PieceChineseNameForPrint(piece));
                    }
                    else
                    {
                        sb.Append(boardChar[j * 9 + i]);
                    }
                }
                sb.Append(System.Environment.NewLine);
            }
            return(sb.ToString());
        }
Exemple #9
0
        ///<summary>
        /// 在某一列上找中兵或中卒的位置编号
        ///</summary>
        ///<param name="piece"></param>
        ///<param name="file">列号</param>
        ///<returns></returns>
        public static int FindMiddlePawn(Board board, int piece, int file)
        {
            int foundPos = -1;
            int numFound = 0;

            for (int rank = 0; rank < 10; rank++)
            {
                int pos = BoardUtil.Pos(file, rank);
                if (board.pieceData[pos] == piece)
                {
                    foundPos = pos;
                    // 如果之前发现过一个兵,又在同一列上找到一个兵,就是“中兵”了
                    if (numFound == 1)
                    {
                        break;
                    }

                    ++numFound;
                }
            }

            return(foundPos);
        }
Exemple #10
0
        /*
         * static void Main(string[] args)
         * {
         *  OpeningBook.CreateOpeningBook();
         *
         *  Board board = Board.CreateStartingBoard();
         *  Move m = OpeningBook.BestMove(board);
         *
         *  int ttt = 0;
         *  while(m!=null)
         *  {
         *      m.Make(board);
         *      Console.WriteLine("---- " + (++ttt) + ": Best Move: " + m + "\n" + board);
         *      m = OpeningBook.BestMove(board);
         *  }
         *
         * // AddPgnFileToOpeningBook(@"..\..\test.pgn");
         *
         *  DirectoryInfo dir = new DirectoryInfo("e:\\11万精品真藏");
         *  FileInfo[] files = dir.GetFiles("*.pgn",SearchOption.AllDirectories);
         *
         *  foreach (FileInfo f in files)
         *  {
         *      Console.WriteLine(f.Name);
         *      //AddPgnFileToOpeningBook(f.FullName);
         *
         *      //if (!CheckPgnFile(f.FullName))
         *      //{
         *      //    Console.WriteLine("!!!FAIL!!!" + f.FullName);
         *      //    File.Delete(f.FullName);
         *      //    Console.ReadKey();
         *      //}
         *  }
         *  Console.ReadKey();
         * }
         *
         */


        private static bool CheckPgnFile(string pgnFilename)
        {
            string[] allmoves = GetAllMovesFromPgnFile(pgnFilename);

            Board board = new Board();

            foreach (string strMove in allmoves)
            {
                try
                {
                    //TODO:  board.CreateMoveFromString(NotationConverter.Convert(board, strMove));
                    Move move = BoardUtil.CreateMoveFromString(board, strMove);
                    board.MakeMove(move);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.ToString() + "\n" + board);
                    return(false);
                }
                // Console.WriteLine("--- " + strMove + " ---");
                // Console.WriteLine(board);
            }
            return(true);
        }
Exemple #11
0
        /// <summary>
        /// 把Move转换为“炮二平五”中文纵列格式的棋谱文本
        /// </summary>
        /// <param name="move">着法</param>
        /// <returns>中文棋谱字符串</returns>
        public static string NotationConvertedFromMove(Board board, Move move)
        {
            string pieceName = PieceName(move.Piece);
            int    fileFrom  = Board.File(move.From);
            int    rankFrom  = Board.Rank(move.From);
            int    fileTo    = Board.File(move.To);
            int    rankTo    = Board.Rank(move.To);
            string strNum    = board.IsRedTurn ? RedDigitString(9 - fileFrom) : BlackDigitString(1 + fileFrom);

            //思路:累计在同一条纵线的上方up或下方down是否有相同棋子,
            //如果都有则为"中",否则根据上下判断"前后".黑棋与红旗"前后"颠倒
            int up   = 0;
            int down = 0;

            for (int rank = 0; rank <= 9; rank++)
            {
                if (rank == rankFrom)
                {
                    continue;
                }
                if (board.pieceData[BoardUtil.Pos(fileFrom, rank)] == move.Piece)
                {
                    if (rank > rankFrom)
                    {
                        ++down;
                    }
                    if (rank < rankFrom)
                    {
                        ++up;
                    }
                }
            }

            // 前2个汉字,这种名字会产生“前炮”、“中兵”、“后马”的效果
            string notation1;

            if (up > 0 && down > 0)
            {
                notation1 = "中";
            }
            else if (up > 0)
            {
                notation1 = board.IsRedTurn ? "前" : notation1 = "后";
            }
            else if (down > 0)
            {
                notation1 = board.IsRedTurn ? "后" : notation1 = "前";
            }
            else
            {
                notation1 = pieceName + strNum;
            }


            // 后2个汉字
            string notation2;

            if (board.IsRedTurn)
            {
                //逻辑说明:首先判断纵向y轴是否改变,负则后退,否则前进.不变则平移.
                int num = rankFrom - rankTo;
                if (num < 0)
                {
                    if (IsTiltPiece(move.Piece))
                    {
                        notation2 = "退" + RedDigitString(Math.Abs(9 - fileTo));
                    }
                    else
                    {
                        notation2 = "退" + RedDigitString(Math.Abs(rankFrom - rankTo));
                    }
                }
                else if (num > 0)
                {
                    if (IsTiltPiece(move.Piece))
                    {
                        notation2 = "进" + RedDigitString(Math.Abs(9 - fileTo));
                    }
                    else
                    {
                        notation2 = "进" + RedDigitString(Math.Abs(rankFrom - rankTo));
                    }
                }
                else // (num == 0)
                {
                    notation2 = "平" + RedDigitString(Math.Abs(9 - fileTo));
                }
            }


            else // 黑方的着法
            {
                //逻辑说明:首先判断纵向y轴是否改变,负则后退,否则前进.不变则平移.
                int num = rankFrom - rankTo;
                if (num > 0)
                {
                    if (IsTiltPiece(move.Piece))
                    {
                        notation2 = "退" + BlackDigitString(Math.Abs(1 + fileTo));
                    }
                    else
                    {
                        notation2 = "退" + BlackDigitString(Math.Abs(rankFrom - rankTo));
                    }
                }
                else if (num < 0)
                {
                    if (IsTiltPiece(move.Piece))
                    {
                        notation2 = "进" + BlackDigitString(Math.Abs(1 + fileTo));
                    }
                    else
                    {
                        notation2 = "进" + BlackDigitString(Math.Abs(rankFrom - rankTo));
                    }
                }
                else //(num == 0)
                {
                    notation2 = "平" + BlackDigitString(Math.Abs(1 + fileTo));
                }
            }
            return(notation1 + notation2);
        }
Exemple #12
0
        /// <summary>
        /// 把中文纵列格式的棋谱转换成Move,例如:炮二平五-->h2e2
        /// </summary>
        /// <param name="board">在走该着法之前的盘面情况</param>
        /// <param name="chNotation">中文纵列标记</param>
        /// <returns>Move。转换过程中出现的错误,都会抛出异常</returns>
        public static Move CreateMoveFromChineseNotation(Board board, string chNotation)
        {
            if (chNotation.Length != 4)
            {
                throw new Exception("着法必须是4个汉字:" + chNotation);
            }

            char first  = chNotation[0];
            char second = chNotation[1];
            char third  = chNotation[2];
            char fourth = chNotation[3];

            int piece = BoardUtil.PieceFromString(chNotation, board.IsRedTurn);

            int startPos = 0;

            // 先要根据前2个汉字找到棋子的初始位置,会有两大类情况,(1)车二;(2)前车
            // 先处理第一种情况:类似这样的“炮二平五”,“马8进7”
            if ("车马炮相仕兵帅象士卒将".Contains(first))
            {
                // 第2个汉字就可以得到起始点的纵列坐标, from 0 to 8
                int startFile = ToFileNum(second);

                // 对于相(象)、士(仕)来说,得找到前面或后面的象、士,因为“相七退五”时,七路上可能会有2个象
                // “仕六进五”也是同样的道理
                if ("相仕象士".Contains(first))
                {
                    // 如果一条线上有2个象,则需要用第三个字符是“进”还是“退”来判断是移动了哪个象
                    if (first == '相' && second == '三' && third == '进')
                    {
                        startPos = Board.G0;
                    }
                    else if (first == '相' && second == '三' && third == '退')
                    {
                        startPos = Board.G4;
                    }
                    else if (first == '相' && second == '七' && third == '进')
                    {
                        startPos = Board.C0;
                    }
                    else if (first == '相' && second == '七' && third == '退')
                    {
                        startPos = Board.C4;
                    }
                    else if (first == '仕' && second == '四' && third == '进')
                    {
                        startPos = Board.F0;
                    }
                    else if (first == '仕' && second == '四' && third == '退')
                    {
                        startPos = Board.F2;
                    }
                    else if (first == '仕' && second == '六' && third == '进')
                    {
                        startPos = Board.D0;
                    }
                    else if (first == '仕' && second == '六' && third == '退')
                    {
                        startPos = Board.D2;
                    }
                    else if (first == '象' && second == '3' && third == '进')
                    {
                        startPos = Board.C9;
                    }
                    else if (first == '象' && second == '3' && third == '退')
                    {
                        startPos = Board.C5;
                    }
                    else if (first == '象' && second == '7' && third == '进')
                    {
                        startPos = Board.G9;
                    }
                    else if (first == '象' && second == '7' && third == '退')
                    {
                        startPos = Board.G5;
                    }
                    else if (first == '士' && second == '4' && third == '进')
                    {
                        startPos = Board.D9;
                    }
                    else if (first == '士' && second == '4' && third == '退')
                    {
                        startPos = Board.D7;
                    }
                    else if (first == '士' && second == '6' && third == '进')
                    {
                        startPos = Board.F9;
                    }
                    else if (first == '士' && second == '6' && third == '退')
                    {
                        startPos = Board.F7;
                    }
                    else
                    {
                        // throw new Exception("error of the position of bishop or advisor");
                        startPos = BoardUtil.FindPosition(board, piece, startFile);
                    }
                }
                else
                {
                    // 按理说,正规的棋谱里这里应该同一纵线上只有一个车、马、炮、兵、卒,但有些不正规的棋谱里会遇到问题
                    // TODO: 以后有时间的,可以多做一些容错性的判断,如果一条纵线上有2个相同类的棋子,但一个棋子无法走动时,则以另一个棋子的着法为准
                    startPos = BoardUtil.FindPosition(board, piece, startFile);
                }
            }
            else // 在这里处理第二大类情况,类似“前炮进二”这样的情况
            {
                // 兵、卒有些特殊,有可能一列中3个兵,这样会有“中兵”或“中卒”的情况出现
                // 2011年无极棋谱\华山棋谱\2011-01-09 青山豹(天罡) 和 一把家族(无极).pgn
                // TODO: 这里面极少可能出现的棋谱,“前1平2”的着法
                if (piece == Board.RED_PAWN || piece == Board.BLACK_PAWN)
                {
                    int col = BoardUtil.Find3PawnFileNum(board, piece);
                    if (first == '中')
                    {
                        startPos = BoardUtil.FindMiddlePawn(board, piece, col);
                    }
                    else if ((first == '前' && board.IsRedTurn) || (first == '后' && !board.IsRedTurn))
                    {
                        startPos = BoardUtil.FindPositionFromBlackToRed(board, piece, col);
                    }
                    else
                    {
                        startPos = BoardUtil.FindPositionFromRedToBlack(board, piece, col);
                    }
                }
                else
                {
                    // 扫描整个棋盘,找到类似“前炮”这样的棋子的位置
                    if ((first == '前' && board.IsRedTurn) || (first == '后' && !board.IsRedTurn))
                    {
                        startPos = BoardUtil.FindPositionFromBlackToRed(board, piece);
                    }
                    else
                    {
                        startPos = BoardUtil.FindPositionFromRedToBlack(board, piece);
                    }
                }
            }

            if (startPos == 0)
            {
                throw new Exception("在盘面上找不到" + first + second + "这枚棋子," + chNotation);
            }

            /////////////////////////////////////////////////////////////////////
            ////////////////////////// 以后都是为了找到终点的坐标了
            /////////////////////////////////////////////////////////////////////

            int startPosFile = Board.File(startPos);
            int startPosRank = Board.Rank(startPos);

            // 根据第3个字符“平、进、退”分别进行相应的处理
            int endFile = -1;
            int endRank = -1;

            if (third == '平')
            {
                if (!IsTiltPiece(piece))
                {
                    endFile = ToFileNum(fourth);
                    if (endFile < 0)
                    {
                        throw new Exception(chNotation + "中的第4个字符错误,应该为大写数字或全角数字");
                    }
                    // 对于“平”着法,起点和终点的行号坐标是一样的
                    endRank = startPosRank;
                }
                else  //士、象、马
                {
                    throw new Exception("士象马不能有平的移动:" + chNotation);
                }
            }
            else if (third == '退')
            {
                if (piece == Board.RED_KNIGHT || piece == Board.BLACK_KNIGHT)
                {
                    endFile = ToFileNum(fourth);
                    if (endFile < 0)
                    {
                        throw new Exception(chNotation + "中的第4个字符错误,应该为大写数字或全角数字");
                    }
                    int diff = Math.Abs(endFile - startPosFile);
                    if (diff == 1)
                    {
                        if (!board.IsRedTurn)
                        {
                            endRank = startPosRank - 2;
                        }
                        else
                        {
                            endRank = startPosRank + 2;
                        }
                    }
                    else if (diff == 2)
                    {
                        if (!board.IsRedTurn)
                        {
                            endRank = startPosRank - 1;
                        }
                        else
                        {
                            endRank = startPosRank + 1;
                        }
                    }
                    else
                    {
                        throw new Exception("马的走法有误:" + chNotation);
                    }
                }
                else if (piece == Board.RED_BISHOP || piece == Board.BLACK_BISHOP)
                {
                    endFile = ToFileNum(fourth);
                    if (endFile < 0)
                    {
                        throw new Exception(chNotation + "中的第4个字符错误,应该为大写数字或全角数字");
                    }
                    int diff = Math.Abs(endFile - startPosFile);
                    if (diff == 2)
                    {
                        if (!board.IsRedTurn)
                        {
                            endRank = startPosRank - 2;
                        }
                        else
                        {
                            endRank = startPosRank + 2;
                        }
                    }
                    else
                    {
                        throw new Exception("相象的走法有误:" + chNotation);
                    }
                }
                else if (piece == Board.RED_ADVISOR || piece == Board.BLACK_ADVISOR)
                {
                    endFile = ToFileNum(fourth);
                    if (endFile < 0)
                    {
                        throw new Exception(chNotation + "中的第4个字符错误,应该为大写数字或全角数字");
                    }
                    int diff = Math.Abs(endFile - startPosFile);
                    if (diff == 1)
                    {
                        if (!board.IsRedTurn)
                        {
                            endRank = startPosRank - 1;
                        }
                        else
                        {
                            endRank = startPosRank + 1;
                        }
                    }
                    else
                    {
                        throw new Exception("仕士的走法有误:" + chNotation);
                    }
                }
                else if (  // 炮、车、帅、兵在纵线上移动时规则都是一样的
                    piece == Board.RED_CANNON || piece == Board.BLACK_CANNON ||
                    piece == Board.RED_ROOK || piece == Board.BLACK_ROOK ||
                    piece == Board.RED_KING || piece == Board.BLACK_KING ||
                    piece == Board.RED_PAWN || piece == Board.BLACK_PAWN)
                {
                    endFile = startPosFile;

                    int diff = ToInt(fourth);
                    if (diff < 0)
                    {
                        throw new Exception(chNotation + "中的第4个字符错误,应该为大写数字或全角数字");
                    }
                    if (!board.IsRedTurn)
                    {
                        endRank = startPosRank - diff;
                    }
                    else
                    {
                        endRank = startPosRank + diff;
                    }
                }
                else
                {
                    throw new Exception("不认识的着法:" + chNotation);
                }
            }
            else // 进
            {
                if (third != '进')
                {
                    throw new Exception(chNotation + "中的第3个字符错误,应该进、退、平");
                }
                if (piece == Board.RED_KNIGHT || piece == Board.BLACK_KNIGHT)
                {
                    endFile = ToFileNum(fourth);
                    if (endFile < 0)
                    {
                        throw new Exception(chNotation + "中的第4个字符错误,应该为大写数字或全角数字");
                    }
                    int diff = Math.Abs(endFile - startPosFile);
                    if (diff == 1)
                    {
                        if (!board.IsRedTurn)
                        {
                            endRank = startPosRank + 2;
                        }
                        else
                        {
                            endRank = startPosRank - 2;
                        }
                    }
                    else if (diff == 2)
                    {
                        if (!board.IsRedTurn)
                        {
                            endRank = startPosRank + 1;
                        }
                        else
                        {
                            endRank = startPosRank - 1;
                        }
                    }
                    else
                    {
                        throw new Exception("马的走法有误:" + chNotation);
                    }
                }
                else if (piece == Board.RED_BISHOP || piece == Board.BLACK_BISHOP)
                {
                    endFile = ToFileNum(fourth);
                    if (endFile < 0)
                    {
                        throw new Exception(chNotation + "中的第4个字符错误,应该为大写数字或全角数字");
                    }
                    int diff = Math.Abs(endFile - startPosFile);
                    if (diff == 2)
                    {
                        if (!board.IsRedTurn)
                        {
                            endRank = startPosRank + 2;
                        }
                        else
                        {
                            endRank = startPosRank - 2;
                        }
                    }
                    else
                    {
                        throw new Exception("相象的走法有误:" + chNotation);
                    }
                }
                else if (piece == Board.RED_ADVISOR || piece == Board.BLACK_ADVISOR)
                {
                    endFile = ToFileNum(fourth);
                    if (endFile < 0)
                    {
                        throw new Exception(chNotation + "中的第4个字符错误,应该为大写数字或全角数字");
                    }
                    int diff = Math.Abs(endFile - startPosFile);
                    if (diff == 1)
                    {
                        if (!board.IsRedTurn)
                        {
                            endRank = startPosRank + 1;
                        }
                        else
                        {
                            endRank = startPosRank - 1;
                        }
                    }
                    else
                    {
                        throw new Exception("士仕的走法有误:" + chNotation);
                    }
                }
                else if (
                    piece == Board.RED_CANNON || piece == Board.BLACK_CANNON ||
                    piece == Board.RED_ROOK || piece == Board.BLACK_ROOK ||
                    piece == Board.RED_KING || piece == Board.BLACK_KING ||
                    piece == Board.RED_PAWN || piece == Board.BLACK_PAWN)
                {
                    endFile = startPosFile;  // !!!!!
                    int diff = ToInt(fourth);
                    if (diff < 0)
                    {
                        throw new Exception(chNotation + "中的第4个字符错误,应该为大写数字或全角数字");
                    }
                    if (!board.IsRedTurn)
                    {
                        endRank = startPosRank + diff;
                    }
                    else
                    {
                        endRank = startPosRank - diff;
                    }
                }
                else
                {
                    throw new Exception("不认识的着法:" + chNotation);
                }
            }
            if (endFile < 0 || endFile >= 9 || endRank < 0 || endRank >= 10)
            {
                throw new Exception("棋子走到棋盘之外了:" + chNotation + "\n" + board);
            }


            int  endPos = BoardUtil.Pos(endFile, endRank);
            Move move   = board.CreateMove(startPos, endPos);

            return(move);
        }