/// <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 }
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; } } } }