Added PGNDatabase and PGNGame classes with support for PGN parsing

This commit is contained in:
Kai S. K. Engelbart 2019-10-09 21:03:39 +02:00
parent c16395fe1f
commit 4e1682ac16
Signed by: kske
GPG Key ID: 8BEB13EC5DF7EF13
2 changed files with 106 additions and 0 deletions

View File

@ -0,0 +1,29 @@
package dev.kske.chess.pgn;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import dev.kske.chess.exception.ChessException;
/**
* Project: <strong>Chess</strong><br>
* File: <strong>PGNDatabase.java</strong><br>
* Created: <strong>4 Oct 2019</strong><br>
* Author: <strong>Kai S. K. Engelbart</strong>
*/
public class PGNDatabase {
private final List<PGNGame> games = new ArrayList<>();
public void load(File pgnFile) {
try (Scanner sc = new Scanner(pgnFile)) {
while (sc.hasNext())
games.add(PGNGame.parse(sc));
} catch (FileNotFoundException | ChessException e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,77 @@
package dev.kske.chess.pgn;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.regex.MatchResult;
import java.util.regex.Pattern;
import dev.kske.chess.board.Board;
import dev.kske.chess.exception.ChessException;
/**
* Project: <strong>Chess</strong><br>
* File: <strong>PGNGame.java</strong><br>
* Created: <strong>22 Sep 2019</strong><br>
* Author: <strong>Kai S. K. Engelbart</strong>
*/
public class PGNGame {
private final Map<String, String> tagPairs = new HashMap<>(7);
private final Board board = new Board();
public static PGNGame parse(Scanner sc) throws ChessException {
PGNGame game = new PGNGame();
MatchResult matchResult;
Pattern tagPairPattern = Pattern.compile("\\[(\\w+) \"(.*)\"]"),
movePattern = Pattern.compile("\\d+\\. (\\S+)\\s(\\S+)"),
nagPattern = Pattern.compile("(\\$\\d{1,3})*"),
terminationMarkerPattern = Pattern.compile("1-0|0-1|1\\/2-1\\/2|\\*");
// Parse tag pairs
while (true) {
if (sc.findInLine(tagPairPattern) != null) {
matchResult = sc.match();
if (matchResult.groupCount() == 2) game.setTag(matchResult.group(0), matchResult.group(1));
else break;
} else break;
sc.nextLine();
}
// Parse movetext
while (true) {
// Skip NAG (Numeric Annotation Glyph)
sc.skip(nagPattern);
// TODO: Parse RAV (Recursive Annotation Variation)
sc.findWithinHorizon(movePattern, 20);
matchResult = sc.match();
if (matchResult.groupCount() > 0) for (int i = 1; i < matchResult.groupCount() + 1; i++) {
game.board.move(matchResult.group(i));
System.out.println(game.board.toFEN());
}
else break;
}
// Parse game termination marker
if (sc.hasNext(terminationMarkerPattern)) {
sc.next(terminationMarkerPattern);
} else throw new ChessException("Game termination marker expected");
return game;
}
public String getTag(String tagName) {
return tagPairs.get(tagName);
}
public boolean hasTag(String tagName) {
return tagPairs.containsKey(tagName);
}
public void setTag(String tagName, String tagValue) {
tagPairs.put(tagName, tagValue);
}
}