/// <summary> /// Traverses the PGN move text section, adding the moves to the model. /// Throws ArgumentException if there is an illegal SAN move. /// </summary> /// <param name="tr">The texr reader which is read from</param> private void TraversePGNMovetext(TextReader tr) { string line; int index, from, to; // skip the empty lines do { line = tr.ReadLine(); } while (line != null && line.Length == 0); // read the lines while (line != null && line.Length > 0) { // it's an escape line, skip it if (line[0] == '%') { line = tr.ReadLine(); continue; } index = 0; // loop through the line characters while (index < line.Length) { // skip the white spaces if (line[index] == ' ') { while (++index < line.Length && line[index] == ' ') ; } // it's a "rest of line" comment, go to the next line if (index < line.Length && line[index] == ';') { line = tr.ReadLine(); index = 0; continue; } // skip the move numbers, the NAG or the game termination tokens if (index < line.Length && ((line[index] >= '0' && line[index] <= '9') || line[index] == '$' || line[index] == '*')) { while (++index < line.Length && line[index] != ' ') ; } // skip the multiline commentaries else if (index < line.Length && line[index] == '{') { while (line[index++] != '}') { if (index >= line.Length) { line = tr.ReadLine(); index = 0; } } } // skip the RAV which can be nested else if (index < line.Length && line[index] == '(') { int depth = 1; while (depth != 0) { if (++index >= line.Length) { line = tr.ReadLine(); index = 0; } if (line[index] == '(') { depth++; } else if (line[index] == ')') { depth--; } } index++; } // if the token it's a move, make it else if (index < line.Length) { from = index; while (++index < line.Length && line[index] != ' ') ; to = index; // remove any !? annotations if (line[to - 1] == '!' || line[to - 1] == '?') { to--; } if (line[to - 1] == '!' || line[to - 1] == '?') { to--; } // make the move model.Make(Utils.GetSANMove(model, line.Substring(from, to - from))); } } line = tr.ReadLine(); } }