/// <summary> /// Ctor /// </summary> /// <param name="game"> FICS Game</param> /// <param name="chessBoardCtl"> Chess board control</param> /// <param name="iMoveTimeout"> Move timeout in second</param> /// <param name="actionMoveTimeOut"> Action to call if move timeout</param> /// <param name="actionGameFinished"> Action to do when game is finished</param> public GameIntf(FICSGame game, SrcChess2.ChessBoardControl chessBoardCtl, int?iMoveTimeout, Action <GameIntf> actionMoveTimeOut, Action <GameIntf, TerminationE, string> actionGameFinished) { Game = game; ChessBoardCtl = chessBoardCtl; BoardCreated = false; m_chessBoard = new SrcChess2.ChessBoard(); m_parser = new SrcChess2.PgnParser(m_chessBoard); m_queueMove = new Queue <Style12MoveLine>(16); m_spanTotalWhiteTime = TimeSpan.Zero; m_spanTotalBlackTime = TimeSpan.Zero; m_spanOriginalMaxTime = (game.PlayerTimeInMin == 0) ? (TimeSpan?)null : TimeSpan.FromMinutes(game.PlayerTimeInMin); m_listInitialMoves = new List <SrcChess2.MoveExt>(128); m_actionGameFinished = actionGameFinished; Termination = TerminationE.None; m_iMoveTimeOut = iMoveTimeout.HasValue ? iMoveTimeout.Value : int.MaxValue; m_pgnGame = new SrcChess2.PgnGame(true /*bAttrList*/, true /*bMoveList*/); m_pgnGame.attrs.Add("Event", "FICS Game " + game.GameId.ToString()); m_pgnGame.attrs.Add("Site", "FICS Server"); m_pgnGame.attrs.Add("White", game.WhitePlayer); m_pgnGame.attrs.Add("Black", game.BlackPlayer); if (game.PlayerTimeInMin != 0 && chessBoardCtl != null) { chessBoardCtl.GameTimer.MaxWhitePlayTime = TimeSpan.FromMinutes(game.PlayerTimeInMin); chessBoardCtl.GameTimer.MaxBlackPlayTime = TimeSpan.FromMinutes(game.PlayerTimeInMin); chessBoardCtl.GameTimer.MoveIncInSec = game.IncTimeInSec; } if (iMoveTimeout != 0 && actionMoveTimeOut != null) { m_timerMoveTimeout = new System.Threading.Timer(TimerCallback, actionMoveTimeOut, System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite); } }
/// <summary> /// Process first game list line /// </summary> /// <param name="strLine"> Received line</param> private void ProcessFirstGameListLine(string strLine) { FICSGame game; bool bSupported; if (!String.IsNullOrWhiteSpace(strLine)) { if (FICSGame.IsLastGameLine(strLine)) { m_state.ResetCommand(); } else { game = FICSGame.ParseGameLine(strLine, out bSupported); if (game != null) { if (bSupported) { m_state.GameList.Add(game); } m_state.Phase++; } } } }
/// <summary> /// Start to observe a game /// </summary> /// <param name="game"> Game to observe</param> /// <param name="chessBoardControl"> Chess board control to associate with the game</param> /// <param name="iTimeOut"> Command timeout in second</param> /// <param name="iMoveTimeOut"> Command timeout in second</param> /// <param name="actionGameFinished"> Action to call when game is finished or null if none</param> /// <param name="strError"> Error if any</param> /// <returns> /// true if succeed, false if game is already defined /// </returns> public bool ObserveGame(FICSGame game, SrcChess2.ChessBoardControl chessBoardControl, int iTimeOut, int?iMoveTimeOut, Action <GameIntf, TerminationE, string> actionGameFinished, out string strError) { bool bRetVal; GameIntf gameIntf; Action <GameIntf> actionMoveTimeOut; if (chessBoardControl == null) { throw new ArgumentNullException(); } if (iMoveTimeOut == 0) { actionMoveTimeOut = null; } else { actionMoveTimeOut = GetTimeOutAction(); } gameIntf = new GameIntf(game, chessBoardControl, iMoveTimeOut, actionMoveTimeOut, actionGameFinished); #if DEBUG iTimeOut = 3600; #endif bRetVal = ObserveGame(gameIntf, iTimeOut, out strError); return(bRetVal); }
/// <summary> /// true if game meets the criteria /// </summary> /// <param name="game"></param> /// <returns></returns> public bool IsGameMeetCriteria(FICSGame game) { bool bRetVal; bRetVal = (string.IsNullOrEmpty(PlayerName) || string.Compare(PlayerName, game.WhitePlayer, true) == 0 || string.Compare(PlayerName, game.BlackPlayer, true) == 0); if (bRetVal) { switch (game.GameType) { case FICSGame.GameTypeE.Blitz: bRetVal = BlitzGame; break; case FICSGame.GameTypeE.Lightning: bRetVal = LightningGame; break; case FICSGame.GameTypeE.Untimed: bRetVal = UntimedGame; break; case FICSGame.GameTypeE.Standard: bRetVal = StandardGame; break; default: bRetVal = false; break; } } if (bRetVal && IsRated) { bRetVal = game.WhiteRating >= MinRating && game.BlackRating >= MinRating; } if (bRetVal && MinTimePerPlayer.HasValue) { bRetVal = game.PlayerTimeInMin >= MinTimePerPlayer; } if (bRetVal && MaxTimePerPlayer.HasValue) { bRetVal = game.PlayerTimeInMin <= MaxTimePerPlayer; } if (bRetVal && MinIncTimePerMove.HasValue) { bRetVal = game.IncTimeInSec >= MinIncTimePerMove; } if (bRetVal && MaxIncTimePerMove.HasValue) { bRetVal = game.IncTimeInSec <= MaxIncTimePerMove; } if (bRetVal) { bRetVal = game.NextMoveCount <= MaxMoveDone; } return(bRetVal); }
/// <summary> /// Ctor /// </summary> /// <param name="game"> Game</param> /// <param name="chessBoardControl"> Chess board control if any</param> /// <param name="streamLog"> Stream where to send the log information</param> /// <param name="eventWaitHandle"> Use to inform background tester the game is terminated</param> /// <param name="iMoveTimeOut"> Move timeout in second</param> /// <param name="actionMoveTimeOut"> Action to call if move timeout</param> public GameIntfTest(FICSGame game, SrcChess2.ChessBoardControl chessBoardControl, System.IO.StreamWriter streamLog, EventWaitHandle eventWaitHandle, int iMoveTimeOut, Action <GameIntf> actionMoveTimeOut) : base(game, chessBoardControl, iMoveTimeOut, actionMoveTimeOut, null /*actionGameTerminated*/) { m_streamLog = streamLog; EventWaitHandle = eventWaitHandle; }
/// <summary> /// Process first game list line /// </summary> /// <param name="strLine"> Received line</param> private void ProcessGameListLine(string strLine) { FICSGame game; bool bSupported; game = FICSGame.ParseGameLine(strLine, out bSupported); if (game != null) { if (bSupported) { m_state.GameList.Add(game); } } else { m_state.ResetCommand(); } }
/// <summary> /// Parse a line /// </summary> /// <param name="strLine"> Line to parse</param> /// <param name="iGameId"> Game ID</param> /// <param name="eTermination"> Termination code if error or if game has ended</param> /// <param name="strTerminationComment"> Termination comment if any</param> /// <param name="strError"> Returned error if any. null if no error detected</param> /// <returns> /// Line or null if not a style12 line or error /// </returns> static public Style12MoveLine ParseLine(string strLine, out int iGameId, out TerminationE eTermination, out string strTerminationComment, out string strError) { Style12MoveLine lineRetVal; string[] arrParts; string strFENLine; ChessBoard.PieceE ePiece; int iLine; int iPos; int[] arrIntVal; eTermination = IsMoveTermination(strLine, out iGameId, out strTerminationComment, out strError); if (eTermination != TerminationE.None) { lineRetVal = null; } else { arrParts = GetLineParts(strLine); if (arrParts == null) { lineRetVal = null; } else { lineRetVal = new Style12MoveLine(); iPos = 63; iLine = 0; arrIntVal = new int[11]; while (iLine < 8 && strError == null) { strFENLine = arrParts[iLine + 1]; if (strFENLine.Length != 8) { strError = "Illegal board definition - bad FEN line size"; } else { foreach (char chr in strFENLine) { if (DecodePiece(chr, out ePiece)) { lineRetVal.Board[iPos--] = ePiece; } else { strError = "Illegal board definition - Unknown piece specification '" + chr + "'"; break; } } } iLine++; } if (strError == null) { switch (arrParts[9]) { case "B": lineRetVal.NextMovePlayer = ChessBoard.PlayerE.Black; break; case "W": lineRetVal.NextMovePlayer = ChessBoard.PlayerE.White; break; default: strError = "Next move player not 'B' or 'W'"; break; } if (strError == null) { if (!lineRetVal.SetBoardStateMask(arrParts[11], ChessBoard.BoardStateMaskE.WRCastling) || !lineRetVal.SetBoardStateMask(arrParts[12], ChessBoard.BoardStateMaskE.WLCastling) || !lineRetVal.SetBoardStateMask(arrParts[13], ChessBoard.BoardStateMaskE.BRCastling) || !lineRetVal.SetBoardStateMask(arrParts[14], ChessBoard.BoardStateMaskE.BLCastling) || !Int32.TryParse(arrParts[15], out arrIntVal[0]) || !Int32.TryParse(arrParts[16], out arrIntVal[1]) || !Int32.TryParse(arrParts[19], out arrIntVal[2]) || !Int32.TryParse(arrParts[20], out arrIntVal[3]) || !Int32.TryParse(arrParts[21], out arrIntVal[4]) || !Int32.TryParse(arrParts[22], out arrIntVal[5]) || !Int32.TryParse(arrParts[23], out arrIntVal[6]) || !Int32.TryParse(arrParts[24], out arrIntVal[7]) || !Int32.TryParse(arrParts[25], out arrIntVal[8]) || !Int32.TryParse(arrParts[26], out arrIntVal[9]) || !Int32.TryParse(arrParts[30], out arrIntVal[10])) { strError = "Illegal value in field."; } else if (arrIntVal[2] < -3 || arrIntVal[2] > 2 || arrIntVal[3] < 0 || arrIntVal[9] < 0 || arrIntVal[10] < 0 || arrIntVal[10] > 1) { strError = "Field value out of range."; } else { lineRetVal.WhitePlayerName = arrParts[17]; lineRetVal.BlackPlayerName = arrParts[18]; lineRetVal.IrreversibleMoveCount = arrIntVal[0]; lineRetVal.GameId = arrIntVal[1]; lineRetVal.RelationWithGame = (RelationWithGameE)arrIntVal[2]; lineRetVal.InitialTime = arrIntVal[3]; lineRetVal.IncrementTime = arrIntVal[4]; lineRetVal.WhiteMaterial = arrIntVal[5]; lineRetVal.BlackMaterial = arrIntVal[6]; lineRetVal.WhiteRemainingTime = arrIntVal[7]; lineRetVal.BlackRemainingTime = arrIntVal[8]; lineRetVal.MoveNumber = arrIntVal[9]; lineRetVal.LastMoveVerbose = arrParts[27]; lineRetVal.LastMoveSpan = FICSGame.ParseTime(arrParts[28].Replace("(", "").Replace(")", "")); lineRetVal.LastMoveSAN = arrParts[29]; lineRetVal.IsFlipped = (arrIntVal[9] == 1); iGameId = lineRetVal.GameId; } } if (strError == null) { if (arrParts.Length >= 33 && Int32.TryParse(arrParts[31], out arrIntVal[0]) && Int32.TryParse(arrParts[32], out arrIntVal[1])) { lineRetVal.IsClockTicking = (arrIntVal[0] == 1); lineRetVal.LagInMS = arrIntVal[1]; } else { lineRetVal.IsClockTicking = true; lineRetVal.LagInMS = 0; } } } if (strError != null) { lineRetVal = null; eTermination = TerminationE.TerminatedWithErr; } } } return(lineRetVal); }
/// <summary> /// Parse a game string coming from the games command /// </summary> /// <param name="str"> Line containing the game information</param> /// <param name="bSupported"> Returned false if the game type is not actually supported</param> /// <returns> /// Game or null if cannot be parsed /// </returns> public static FICSGame ParseGameLine(string str, out bool bSupported) { FICSGame gameRetVal; int iPos; int iEnclosedPos; int iGameId; string strTok; string strEnclosedStr; char chr; bool bExam; bSupported = true; if (String.IsNullOrWhiteSpace(str)) { gameRetVal = null; bSupported = false; } else { try { bExam = false; iPos = 0; strTok = GetNextToken(str, ref iPos); if (!Int32.TryParse(strTok, out iGameId)) { gameRetVal = null; } else { gameRetVal = new FICSGame(); gameRetVal.GameId = iGameId; strTok = GetNextToken(str, ref iPos); bExam = strTok.StartsWith("("); if (bExam || strTok == "games") { gameRetVal = null; bSupported = false; } else { gameRetVal.WhiteRating = ParseRating(strTok); gameRetVal.WhitePlayer = GetNextToken(str, ref iPos); gameRetVal.BlackRating = ParseRating(GetNextToken(str, ref iPos)); gameRetVal.BlackPlayer = GetNextToken(str, ref iPos); strEnclosedStr = GetNextEnclosedToken(str, ref iPos, '[', ']'); if (String.IsNullOrEmpty(strEnclosedStr)) { gameRetVal = null; bSupported = false; } else { iEnclosedPos = 0; chr = GetNextChar(strEnclosedStr, ref iEnclosedPos); if (chr != ' ' && chr != 'p') { gameRetVal = null; bSupported = false; } else { gameRetVal.IsPrivate = (chr == 'p'); gameRetVal.GameType = ParseGameType(GetNextChar(strEnclosedStr, ref iEnclosedPos), ref bSupported); gameRetVal.IsRated = GetNextChar(strEnclosedStr, ref iEnclosedPos) == 'r'; gameRetVal.PlayerTimeInMin = Int32.Parse(GetNextToken(strEnclosedStr, ref iEnclosedPos)); gameRetVal.IncTimeInSec = Int32.Parse(GetNextToken(strEnclosedStr, ref iEnclosedPos)); gameRetVal.WhiteTimeSpan = ParseTime(GetNextToken(str, ref iPos)); GetNextNonWhiteChar(str, ref iPos); gameRetVal.BlackTimeSpan = ParseTime(GetNextToken(str, ref iPos)); strEnclosedStr = GetNextEnclosedToken(str, ref iPos, '(', ')'); if (String.IsNullOrEmpty(strEnclosedStr)) { gameRetVal = null; bSupported = false; } else { iEnclosedPos = 0; gameRetVal.WhiteMaterialPoint = Int32.Parse(GetNextDigitToken(strEnclosedStr, ref iEnclosedPos)); GetNextNonWhiteChar(strEnclosedStr, ref iEnclosedPos); gameRetVal.BlackMaterialPoint = Int32.Parse(GetNextDigitToken(strEnclosedStr, ref iEnclosedPos)); gameRetVal.NextMovePlayer = ParsePlayer(GetNextToken(str, ref iPos)[0]); gameRetVal.NextMoveCount = Int32.Parse(GetNextToken(str, ref iPos)); } } } } } } catch (System.Exception) { gameRetVal = null; } } return(gameRetVal); }
/// <summary> /// Parse the initial move /// </summary> /// <param name="strLine"> Line to parse</param> /// <param name="strError"> Returned error if any</param> /// <returns> /// true if succeed, false if error, null if all starting moves has been found /// </returns> public bool?ParseInitialMove(string strLine, out string strError) { bool? bRetVal; int iHalfMoveIndex; int iMoveIndex; string strWhiteMove; string strBlackMove; TimeSpan?spanWhiteTime; TimeSpan?spanBlackTime; SrcChess2.MoveExt move; iHalfMoveIndex = m_chessBoard.MovePosStack.Count; iMoveIndex = iHalfMoveIndex / 2 + 1; bRetVal = FICSGame.ParseMoveLine(iMoveIndex, strLine, out strWhiteMove, out spanWhiteTime, out strBlackMove, out spanBlackTime, out strError); if (bRetVal == true) { if (!String.IsNullOrEmpty(strWhiteMove)) { if (!m_parser.ApplySANMoveToBoard(m_pgnGame, strWhiteMove, out move)) { bRetVal = false; strError = "Illegal move - " + strWhiteMove; } else { m_listInitialMoves.Add(move); if (!String.IsNullOrEmpty(strBlackMove)) { if (!m_parser.ApplySANMoveToBoard(m_pgnGame, strBlackMove, out move)) { bRetVal = false; strError = "Illegal move - " + strBlackMove; } else { m_listInitialMoves.Add(move); } } } } if (bRetVal == true) { if (spanWhiteTime.HasValue) { m_spanTotalWhiteTime += spanWhiteTime.Value; } if (spanBlackTime.HasValue) { m_spanTotalBlackTime += spanBlackTime.Value; } } } if (bRetVal == false && strError != null) { ShowError(strError); } return(bRetVal); }