load_pgn method

bool load_pgn(
  1. String? pgn, [
  2. Map? options
])

Load the moves of a game stored in Portable Game Notation. options is an optional parameter that contains a 'newline_char' which is a string representation of a RegExp (and should not be pre-escaped) and defaults to '\r?\n'). Returns true if the PGN was parsed successfully, otherwise false.

Implementation

bool load_pgn(String? pgn, [Map? options]) {
  String mask(str) {
    return str.replaceAll(RegExp(r'\\'), '\\');
  }

  /* convert a move from Standard Algebraic Notation (SAN) to 0x88
     * coordinates
    */
  Move? move_from_san(move) {
    final moves = generate_moves();
    for (var i = 0, len = moves.length; i < len; i++) {
      /* strip off any trailing move decorations: e.g Nf3+?! */
      if (move.replaceAll(RegExp(r'[+#?!=]+$'), '') ==
          move_to_san(moves[i]).replaceAll(RegExp(r'[+#?!=]+$'), '')) {
        return moves[i];
      }
    }
    return null;
  }

  Move? get_move_obj(move) {
    return move_from_san(trim(move));
  }

  /*has_keys(object) {
      bool has_keys = false;
      for (var key in object) {
        has_keys = true;
      }
      return has_keys;
    }*/

  Map<String, String> parse_pgn_header(header, [Map? options]) {
    final newline_char =
        (options != null && options.containsKey('newline_char'))
            ? options['newline_char']
            : '\r?\n';
    final header_obj = <String, String>{};
    final headers = header.split(RegExp(newline_char));
    var key = '';
    var value = '';

    for (var i = 0; i < headers.length; i++) {
      var keyMatch = RegExp(r'^\[([A-Z][A-Za-z]*)\s.*\]$');
      var temp = keyMatch.firstMatch(headers[i]);
      if (temp != null) {
        key = temp[1]!;
      }
      //print(key);
      var valueMatch = RegExp(r'^\[[A-Za-z]+\s"(.*)"\]$');
      temp = valueMatch.firstMatch(headers[i]);
      if (temp != null) {
        value = temp[1]!;
      }
      //print(value);
      if (trim(key).isNotEmpty) {
        header_obj[key] = value;
      }
    }

    return header_obj;
  }

  final newline_char =
      (options != null && options.containsKey('newline_char'))
          ? options['newline_char']
          : '\r?\n';
  //var regex = new RegExp(r'^(\[.*\]).*' + r'1\.'); //+ r"1\."); //+ mask(newline_char));

  final indexOfMoveStart = pgn!.indexOf(RegExp(newline_char + r'\d+\.{1,3}'));

  /* get header part of the PGN file */
  String? header_string;
  if (indexOfMoveStart != -1) {
    header_string = pgn.substring(0, indexOfMoveStart).trim();
  }

  /* no info part given, begins with moves */
  if (header_string == null || header_string[0] != '[') {
    header_string = '';
  }

  /* parse PGN header */
  final headers = parse_pgn_header(header_string, options);
  if (headers.containsKey('FEN')) {
    load(headers['FEN']!);
  } else {
    reset();
  }
  for (var key in headers.keys) {
    set_header([key, headers[key]]);
  }

  /* delete header to get the moves */
  var ms = pgn
      .replaceAll(header_string, '')
      .replaceAll(RegExp(mask(newline_char)), ' ');

  /* delete comments */
  ms = ms.replaceAll(RegExp(r'({[^}]+\})+?'), '');

  /* delete move numbers */
  ms = ms.replaceAll(RegExp(r'\d+\.{1,3}'), '');

  /* delete recursive annotation variations */
  RegExp regExp = RegExp(r'(\([^\(\)]+\))+?');
  var variations = regExp.allMatches(ms).toList();
  while (variations.isNotEmpty) {
    ms = ms.replaceAll(regExp, '');
    variations = regExp.allMatches(ms).toList();
  }

  /* trim and get array of moves */
  var moves = trim(ms).split(RegExp(r'\s+'));

  /* delete empty entries */
  moves = moves.join(',').replaceAll(RegExp(r',,+'), ',').split(',');
  var move;

  for (var half_move = 0; half_move < moves.length - 1; half_move++) {
    move = get_move_obj(moves[half_move]);

    /* move not possible! (don't clear the board to examine to show the
       * latest valid position)
       */
    if (move == null) {
      return false;
    } else {
      make_move(move);
    }
  }

  /* examine last move */
  move = moves[moves.length - 1];
  if (POSSIBLE_RESULTS.contains(move)) {
    if (!header.containsKey('Result')) {
      set_header(['Result', move]);
    }
  } else {
    final moveObj = get_move_obj(move);
    if (moveObj == null) {
      return false;
    } else {
      make_move(moveObj);
    }
  }
  return true;
}