/// <summary>
        /// 解析一条FEN字符串
        /// </summary>
        /// <param name="str"></param>
        public virtual void Parse(string str)
        {
            string[] note = str.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

            #region 16.1.3.1: Parse piece placement data

            int dot   = 1;
            int index = 0;

            string[] row = note[0].Split('/');
            if (row.Length != 8)
            {
                throw new ArgumentException("Invalid board specification, " + row.Length + " ranks are defined, there should be 8.");
            }

            foreach (string line in row)
            {
                index = 0;
                foreach (char achar in line)
                {
                    if (achar >= '0' && achar <= '9')
                    {
                        index += (int)(achar - '0');
                    }
                    else
                    {
                        if (Enums.ToPieceType(achar) != Enums.PieceType.None)
                        {
                            if (index > 7)  // This check needed here to avoid overrunning index below under some error conditions.
                            {
                                throw new ArgumentException("Invalid board specification, rank " + (dot / 8 + 1) + " has more then 8 items specified.");
                            }
                            this.SetByPosition(dot + index, achar);
                        }
                        index++;
                    }
                }

                if (index == 0) // Allow null lines = /8/
                {
                    index += 8;
                }

                if (index != 8)
                {
                    throw new ArgumentException("Invalid board specification, rank " + (dot / 8 + 1) + " has " + index + " items specified, there should be 8.");
                }

                dot += 8;
            }

            #endregion

            #region 16.1.3.2: Parse active color

            if (note.Length >= 2)
            {
                // 16.1.3.2: Parse active color
                if (note[1].Length > 0)
                {
                    char colorchar = Char.ToLower(note[1][0]);
                    if (colorchar.Equals('w') || colorchar.Equals('b'))
                    {
                        GameSide = Enums.ToGameSide(colorchar);
                    }
                    else
                    {
                        throw new ArgumentException("Invalid color designation, use w or b as 2nd field separated by spaces.");
                    }

                    if (note[1].Length != 1)
                    {
                        throw new ArgumentException("Invalid color designation, 2nd field is " + note[1].Length + " chars long, only 1 allowed.");
                    }
                }
            }

            #endregion

            #region 16.1.3.3: Parse castling availability

            if (note.Length >= 3)
            {
                foreach (char achar in note[2])
                {
                    switch (achar)
                    {
                    case 'K':
                        this.WhiteKingCastlingAvailability = true;
                        break;

                    case 'Q':
                        this.WhiteQueenCastlingAvailability = true;
                        break;

                    case 'k':
                        this.BlackKingCastlingAvailability = true;
                        break;

                    case 'q':
                        this.BlackQueenCastlingAvailability = true;
                        break;

                    case '-':
                        break;

                    default:
                        throw new Exception("Invalid castle privileges designation, use: KQkq or -");
                    }
                }
            }

            #endregion

            #region 16.1.3.4: Parse en passant target square such as "e3"
            try
            {
                if (note.Length >= 4)
                {
                    // 16.1.3.4: Parse en passant target square such as "e3"
                    if (note[3].Length == 2)
                    {
                        if (GameSide == Enums.GameSide.White)
                        {
                            if (note[3][1] != '6')
                            {
                                throw new Exception("Invalid target square for white En passant captures: " + this.EnPassantTargetPosition.ToString());
                            }
                        }
                        else
                        {
                            if (note[3][1] != '3')
                            {
                                throw new Exception("Invalid target square for black En passant captures: " + this.EnPassantTargetPosition.ToString());
                            }
                        }
                    }
                    this.EnPassantTargetPosition = Position.Parse(note[3]);
                }
            }
            catch { }
            #endregion

            #region 16.1.3.5: Parse halfmove clock, count of half-move since last pawn advance or unit capture
            try
            {
                if (note.Length >= 5)
                {
                    // 16.1.3.5: Parse halfmove clock, count of half-move since last pawn advance or unit capture
                    this.HalfMoveClock = Int16.Parse(note[4]);
                }
            }
            catch { }
            #endregion

            #region 16.1.3.6: Parse fullmove number, increment after each black move
            try
            {
                if (note.Length >= 6)
                {
                    // 16.1.3.6: Parse fullmove number, increment after each black move
                    this.FullMoveNumber = Int16.Parse(note[5]);
                }
            }
            catch { }
            #endregion
        }
Beispiel #2
0
        public void Parse(string value)
        {
            #region Starting

            if (string.IsNullOrEmpty(value))
            {
                throw new ArgumentNullException();
            }
            value = value.Trim();
            if (value.Length < 2 || value == "\r\n")
            {
                throw new ArgumentOutOfRangeException(value);
            }
            this.Actions.Add(Enums.Action.General);

            #endregion

            #region 针对尾部标记符进行一些操作,并返回裁剪掉尾部标记符的Value值
            foreach (string flagword in Servicer.Flags)
            {
                if (value.EndsWith(flagword))
                {
                    if (flagword.Equals("+"))//Qh5+
                    {
                        this.Actions.Add(Enums.Action.Check);
                    }
                    value = value.Substring(0, value.LastIndexOf(flagword));//裁剪掉尾部标记符
                    break;
                }
            }
            #endregion

            bool isMatch = false;
            foreach (var item in Servicer.StepRegex)
            {
                if (item.Second.IsMatch(value))
                {
                    switch (item.First)
                    {
                        #region case
                    case Servicer.AsStep.As_e4:
                        this.PieceType      = Enums.ToPieceType(this.GameSide);
                        this.TargetPosition = Position.Parse(value);
                        isMatch             = true;
                        break;

                    case Servicer.AsStep.As_Rd7:
                        this.PieceType      = Enums.ToPieceType(value[0], this.GameSide);
                        this.TargetPosition = Position.Parse(value.Substring(value.Length - 2));
                        isMatch             = true;
                        break;

                    case Servicer.AsStep.As_Rxa2:
                        this.PieceType = Enums.ToPieceType(value[0], this.GameSide);
                        this.Actions.Add(Enums.Action.Capture);
                        this.TargetPosition = Position.Parse(value.Substring(value.Length - 2));
                        isMatch             = true;
                        break;

                    case Servicer.AsStep.As_Rbe1:
                        this.PieceType      = Enums.ToPieceType(value[0], this.GameSide);
                        this.SourceChar     = value[1];
                        this.TargetPosition = Position.Parse(value.Substring(value.Length - 2));
                        isMatch             = true;
                        break;

                    case Servicer.AsStep.As_N1c3:
                        this.PieceType      = Enums.ToPieceType(value[0], this.GameSide);
                        this.SourceChar     = value[1];
                        this.TargetPosition = Position.Parse(value.Substring(value.Length - 2));
                        isMatch             = true;
                        break;

                    case Servicer.AsStep.As_hxg6:
                        this.PieceType  = Enums.ToPieceType(this.GameSide);
                        this.SourceChar = value[0];
                        this.Actions.Add(Enums.Action.Capture);
                        this.TargetPosition = Position.Parse(value.Substring(value.Length - 2));
                        isMatch             = true;
                        break;

                    case Servicer.AsStep.As_Ngxf6:
                        this.PieceType  = Enums.ToPieceType(value[0], this.GameSide);
                        this.SourceChar = value[1];
                        this.Actions.Add(Enums.Action.Capture);
                        this.TargetPosition = Position.Parse(value.Substring(value.Length - 2));
                        isMatch             = true;
                        break;

                    case Servicer.AsStep.As_R8xf5:    //N1c3
                        this.PieceType  = Enums.ToPieceType(value[0], this.GameSide);
                        this.SourceChar = value[1];
                        this.Actions.Add(Enums.Action.Capture);
                        this.TargetPosition = Position.Parse(value.Substring(value.Length - 2));
                        isMatch             = true;
                        break;

                    case Servicer.AsStep.As_e8_Q:
                        this.PieceType = Enums.ToPieceType(this.GameSide);
                        this.Actions.Add(Enums.ToPromoteAction(value[value.Length - 1]));
                        this.TargetPosition = Position.Parse(value.Substring(value.Length - 4, 2));
                        isMatch             = true;
                        break;

                    case Servicer.AsStep.As_exf8_Q:
                        this.PieceType  = Enums.ToPieceType(this.GameSide);
                        this.SourceChar = value[0];
                        this.Actions.Add(Enums.Action.Capture);
                        this.Actions.Add(Enums.ToPromoteAction(value[value.Length - 1]));
                        this.TargetPosition = Position.Parse(value.Substring(value.Length - 4, 2));
                        isMatch             = true;
                        break;

                    case Servicer.AsStep.As_O_O:
                        this.PieceType = Enums.PieceType.None;
                        this.Actions.Add(Enums.Action.KingSideCastling);
                        isMatch = true;
                        break;

                    case Servicer.AsStep.As_O_O_O:
                        this.PieceType = Enums.PieceType.None;
                        this.Actions.Add(Enums.Action.QueenSideCastling);
                        isMatch = true;
                        break;
                        #endregion
                    }
                    if (isMatch == true)
                    {
                        break;
                    }
                }
            }
        }