From 4e1682ac16889c85952c6f7f496668d564b7e284 Mon Sep 17 00:00:00 2001 From: kske Date: Wed, 9 Oct 2019 21:03:39 +0200 Subject: [PATCH] Added PGNDatabase and PGNGame classes with support for PGN parsing --- src/dev/kske/chess/pgn/PGNDatabase.java | 29 ++++++++++ src/dev/kske/chess/pgn/PGNGame.java | 77 +++++++++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 src/dev/kske/chess/pgn/PGNDatabase.java create mode 100644 src/dev/kske/chess/pgn/PGNGame.java diff --git a/src/dev/kske/chess/pgn/PGNDatabase.java b/src/dev/kske/chess/pgn/PGNDatabase.java new file mode 100644 index 0000000..61ccdc6 --- /dev/null +++ b/src/dev/kske/chess/pgn/PGNDatabase.java @@ -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: Chess
+ * File: PGNDatabase.java
+ * Created: 4 Oct 2019
+ * Author: Kai S. K. Engelbart + */ +public class PGNDatabase { + + private final List 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(); + } + } +} diff --git a/src/dev/kske/chess/pgn/PGNGame.java b/src/dev/kske/chess/pgn/PGNGame.java new file mode 100644 index 0000000..e800a3c --- /dev/null +++ b/src/dev/kske/chess/pgn/PGNGame.java @@ -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: Chess
+ * File: PGNGame.java
+ * Created: 22 Sep 2019
+ * Author: Kai S. K. Engelbart + */ +public class PGNGame { + + private final Map 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); + } +}