/// <summary> /// Read games from chess games format. /// </summary> /// <param name="filePath">The file path of the chess games file.</param> /// <returns>a list of chess games</returns> public IEnumerable <ChessGame> Deserialize(string filePath) { var games = new List <ChessGame>(); using (var reader = new StreamReader(filePath)) { string buffer; while ((buffer = reader.ReadLine()) != null) { var game = new ChessGame(); // parse winner char winnerContent = buffer[buffer.IndexOf('w') + 2]; buffer = buffer.Substring(0, buffer.LastIndexOf(',')); switch (winnerContent) { case 'w': game.Winner = ChessColor.White; break; case 'b': game.Winner = ChessColor.Black; break; default: game.Winner = null; break; } // parse the draws and apply them to the game var drawsOfGame = buffer.Trim().Split(',').Select(x => new ChessDraw(int.Parse(x.Trim(), System.Globalization.NumberStyles.HexNumber))).ToList(); drawsOfGame.ForEach(x => game.ApplyDraw(x)); games.Add(game); } } return(games); }
/// <summary> /// <para>Compute the win rate of each (board, draw) tuple onto the given chess games by grouping those tuples for multiple games.</para> /// WARNING: This function might use lots of RAM to speed up the computation!!! (about 11 GB for evaluating 360000 games) /// </summary> /// <param name="games">The chess games to be evaluated.</param> /// <returns>a list of win rates for each (board, draw) tuple onto the given chess games</returns> public IEnumerable <WinRateInfo> GamesToWinRates(IEnumerable <ChessGame> games) { // TODO: use Trill API here ... instead of Linq ... var drawsCache = games.Where(game => game.Winner != null).AsParallel().SelectMany(game => { var drawsXWinner = new List <Tuple <Tuple <string, ChessDraw>, ChessColor> >(); var winningSide = game.Winner.Value; var tempGame = new ChessGame(); foreach (var draw in game.AllDraws) { var board = (IChessBoard)((ICloneable)tempGame.Board).Clone(); drawsXWinner.Add(new Tuple <Tuple <string, ChessDraw>, ChessColor>(new Tuple <string, ChessDraw>(board.ToHash(), draw), winningSide)); tempGame.ApplyDraw(draw); } return(drawsXWinner); }).ToList(); var winRates = drawsCache.GroupBy(x => x.Item1).Where(x => x.Count() >= 5).AsParallel().Select(group => { int drawingSideWins = group.Count(x => x.Item2 == group.Key.Item2.DrawingSide); int totalGames = group.Count(); double winRate = (double)drawingSideWins / totalGames; return(new WinRateInfo() { Draw = group.Key.Item2, BoardHash = group.Key.Item1, WinRate = winRate, AnalyzedGames = totalGames }); }) .ToList(); return(winRates); }
/// <summary> /// Start a new game with the two players of the session and continue until the game is over. /// </summary> /// <returns>return the chess game log with all draws etc.</returns> public ChessGame ExecuteGame() { // initialize new chess game Game = new ChessGame(); // continue until the game is over while (!Game.GameStatus.IsGameOver()) { // determin the drawing player var drawingPlayer = Game.SideToDraw == ChessColor.White ? WhitePlayer : BlackPlayer; // init loop variables bool isDrawValid; ChessDraw draw; do { // get the draw from the player draw = drawingPlayer.GetNextDraw(Game.Board, Game.LastDrawOrDefault); isDrawValid = Game.ApplyDraw(draw, true); }while (!isDrawValid); // raise board changed event BoardChanged?.Invoke(Game.Board); } // return the chess game, so it can be logged, etc. return(Game); }
/// <summary> /// Retrieve the chess game data from a single PGN game log. /// </summary> /// <param name="log">The PGN game log to be parsed.</param> /// <returns>The chess game data to was parsed.</returns> private ChessGame parseGameLog(string log) { var game = new ChessGame(); log = log.Trim(); int i = 0; int nextComment = log.IndexOf('{'); // parse all draws of the game log while (i < log.Length) { // determine the start and end of the draw data to be parsed int start = log.IndexOf('.', i) + 1; int end = (log.IndexOf('.', start) > 0) ? (log.IndexOf('.', start) - 1) : (log.Length); // get text of the draw data (usually 1 or 2 draws) string drawText = ((end > 0) ? log.Substring(start, end - start) : log.Substring(start)).Trim(); // ignore comments if (nextComment > 0 && end > nextComment) { int commentEnd = log.IndexOf('}', nextComment); end = (log.IndexOf('.', commentEnd) > 0) ? (log.IndexOf('.', commentEnd) - 1) : (log.Length); drawText = log.Substring(start, nextComment - start).Trim() + log.Substring(commentEnd + 1, end - commentEnd - 1); nextComment = log.IndexOf('{', commentEnd); } // parse draws of this round (each white and black side) var draws = parseRound(game, drawText); // apply white and black draw to the chess board foreach (var draw in draws) { game.ApplyDraw(draw); } // stop if there was a parsing error / no draw content is left to be parsed if (draws?.Count() == 0) { break; } // update index i = end; } // determine the winning side int gameSeriesScoreIndex = log.LastIndexOf(" ") + 1; string gameSeriesScore = log.Substring(gameSeriesScoreIndex, log.Length - gameSeriesScoreIndex); game.Winner = gameSeriesScore.Equals("1-0") ? ChessColor.White : (gameSeriesScore.Equals("0-1") ? (ChessColor?)ChessColor.Black : null); // TODO: extend parser logic for game scores other than '1-0', '0-1' and '1/2, 1/2' return(game); }
/// <summary> /// Try to submit the a chess draw if it is valid. /// </summary> /// <param name="draw">The draw to be submitted</param> /// <returns>a boolean indicating whether the submitted chess draw is valid</returns> public bool TrySubmitDraw(ChessDraw draw) { // try to apply the chess draw bool success = _game.ApplyDraw(draw, true); // release the mutex of the waiting if (success && _isWaiting) { _isWaiting = false; _mutexWait.ReleaseMutex(); } return(success); }
private ChessGame prepareGame(List <Tuple <ChessPosition, ChessPosition> > moves) { // init a chess board in start formation var game = new ChessGame(); ChessDraw lastDraw = new ChessDraw(); // apply the moves to the chess board foreach (var move in moves) { lastDraw = new ChessDraw(game.Board, move.Item1, move.Item2); game.ApplyDraw(lastDraw); var status = ChessDrawSimulator.Instance.GetCheckGameStatus(game.Board, lastDraw); Assert.True(status == ChessGameStatus.Check || status == ChessGameStatus.None); } return(game); }