loadPgn method
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
loadPgn(String pgn, [Map? options]) {
mask(str) {
return str.replaceAll(new RegExp(r"\\"), '\\');
}
/* convert a move from Standard Algebraic Notation (SAN) to 0x88
* coordinates
*/
moveFromSan(move) {
var moves = generateMoves();
for (var i = 0, len = moves.length; i < len; i++) {
/* strip off any trailing move decorations: e.g Nf3+?! */
if (move.replaceAll(new RegExp(r"[+#?!=]+$"), '') ==
moveToSan(moves[i]).replaceAll(new RegExp(r"[+#?!=]+$"), '')) {
return moves[i];
}
}
return null;
}
getMoveObj(move) {
return moveFromSan(trim(move));
}
/*has_keys(object) {
bool has_keys = false;
for (var key in object) {
has_keys = true;
}
return has_keys;
}*/
parsePgnHeader(header, [Map? options]) {
var newlineChar = (options != null && options.containsKey("newline_char"))
? options['newline_char']
: '\r?\n';
var headerObj = {};
var headers = header.split(newlineChar);
String key = '';
String value = '';
for (var i = 0; i < headers.length; i++) {
RegExp keyMatch = new RegExp(r"^\[([A-Z][A-Za-z]*)\s.*\]$");
var temp = keyMatch.firstMatch(headers[i]);
if (temp != null) {
key = temp[1]!;
}
//print(key);
RegExp valueMatch = new RegExp(r'^\[[A-Za-z]+\s"(.*)"\]$');
temp = valueMatch.firstMatch(headers[i]);
if (temp != null) {
value = temp[1]!;
}
//print(value);
if (trim(key).length > 0) {
headerObj[key] = value;
}
}
return headerObj;
}
var newlineChar = (options != null && options.containsKey("newline_char"))
? options["newline_char"]
: '\r?\n';
//var regex = new RegExp(r'^(\[.*\]).*' + r'1\.'); //+ r"1\."); //+ mask(newline_char));
int indexOfMoveStart = pgn.indexOf(new RegExp(newlineChar + r"1\."));
/* get header part of the PGN file */
String? headerString;
if (indexOfMoveStart != -1) {
headerString = pgn.substring(0, indexOfMoveStart).trim();
}
/* no info part given, begins with moves */
if (headerString == null || headerString[0] != '[') {
headerString = '';
}
reset();
/* parse PGN header */
var headers = parsePgnHeader(headerString, options);
for (var key in headers.keys) {
setHeader([key, headers[key]]);
}
/* delete header to get the moves */
var ms = pgn
.replaceAll(headerString, '')
.replaceAll(new RegExp(mask(newlineChar)), ' ');
/* delete comments */
ms = ms.replaceAll(new RegExp(r"(\{[^}]+\})+?"), '');
/* delete move numbers */
ms = ms.replaceAll(new RegExp(r"\d+\."), '');
/* trim and get array of moves */
var moves = trim(ms).split(new RegExp(r"\s+"));
/* delete empty entries */
moves = moves.join(',').replaceAll(new RegExp(r",,+"), ',').split(',');
var move;
for (var halfMove = 0; halfMove < moves.length - 1; halfMove++) {
move = getMoveObj(moves[halfMove]);
/* move not possible! (don't clear the board to examine to show the
* latest valid position)
*/
if (move == null) {
return false;
} else {
makeMove(move);
}
}
/* examine last move */
move = moves[moves.length - 1];
if (POSSIBLE_RESULTS.contains(move)) {
if (!header.containsKey("Result")) {
setHeader(['Result', move]);
}
} else {
var moveObj = getMoveObj(move);
if (moveObj == null) {
return false;
} else {
makeMove(moveObj);
}
}
return true;
}