From 481bb50c6aae7671a5c039479346017d32c15ac1 Mon Sep 17 00:00:00 2001 From: ErdoganSeref Date: Tue, 23 Jul 2024 00:35:39 +0200 Subject: [PATCH 1/9] Implement helper data structure Add dependency to Trie data structure Implement longest common prefix search --- build.sbt | 5 +- src/main/java/game/OpeningTrie.java | 92 ++++++++++++++++++++++++++++ src/test/scala/OpeningTrieTest.scala | 19 ++++++ 3 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 src/main/java/game/OpeningTrie.java create mode 100644 src/test/scala/OpeningTrieTest.scala diff --git a/build.sbt b/build.sbt index 5cf589f..8bbf061 100644 --- a/build.sbt +++ b/build.sbt @@ -4,7 +4,10 @@ name := "compression" organization := "org.lichess" version := "1.10" resolvers += "lila-maven" at "https://raw.githubusercontent.com/ornicar/lila-maven/master" -libraryDependencies += "org.specs2" %% "specs2-core" % "4.17.0" % Test +libraryDependencies ++= Seq( + "org.specs2" %% "specs2-core" % "4.17.0" % Test, + "org.apache.commons" % "commons-collections4" % "4.5.0-M2", +) scalacOptions := Seq( "-encoding", "utf-8", diff --git a/src/main/java/game/OpeningTrie.java b/src/main/java/game/OpeningTrie.java new file mode 100644 index 0000000..4ad95be --- /dev/null +++ b/src/main/java/game/OpeningTrie.java @@ -0,0 +1,92 @@ +package org.lichess.compression.game; + +import org.apache.commons.collections4.Trie; +import org.apache.commons.collections4.trie.PatriciaTrie; + +import java.util.*; + +public class OpeningTrie { + private final int bitVectorLength; + private final int maxOpeningPlies; + private final Trie openingTrie; + + public OpeningTrie(Map openingToCode, int bitVectorLength) { + this.maxOpeningPlies = getMaxOpeningPlies(openingToCode); + this.bitVectorLength = bitVectorLength; + this.openingTrie = buildOpeningTrie(openingToCode); + } + + public BitSet get(String opening) { + return openingTrie.get(opening); + } + + public Optional findLongestCommonOpening(String pgnMoves[]) { + String openingMoves[] = Arrays.copyOf(pgnMoves, maxOpeningPlies); + Optional currentLongestCommonOpening = Optional.empty(); + long currentLongestCommonOpeningLength = 0; + int fromIndex = 0; + int toIndex = openingMoves.length; + while (toIndex >= fromIndex) { + int middleIndex = Math.floorDiv(fromIndex + toIndex, 2); + StringBuilder openingBuilder = new StringBuilder(); + for (int i = 0; i <= middleIndex; i++) { + openingBuilder.append(openingMoves[i]); + openingBuilder.append(' '); + } + String opening = openingBuilder.toString(); + Set commonOpenings = openingTrie.prefixMap(opening).keySet(); + if (commonOpenings.isEmpty()) { + toIndex = middleIndex - 1; + } + else { + String longestCommonOpening = commonOpenings + .stream() + .max(Comparator.comparingLong(o -> o.chars().filter(c -> c == ' ').count())) + .orElseThrow(); + long longestCommonOpeningLength = longestCommonOpening.chars().filter(c -> c == ' ').count(); + if (longestCommonOpeningLength > currentLongestCommonOpeningLength) { + currentLongestCommonOpening = Optional.of(longestCommonOpening); + currentLongestCommonOpeningLength = longestCommonOpeningLength; + } + fromIndex = middleIndex + 1; + } + } + return currentLongestCommonOpening; + } + + private int getMaxOpeningPlies(Map openingToCode) { + return openingToCode + .keySet() + .stream() + .map(opening -> opening.split("\\s+").length) + .max(Integer::compare) + .orElse(0); + } + + private Trie buildOpeningTrie(Map openingToCode) { + Trie openingTrie = new PatriciaTrie<>(); + for (String opening : openingToCode.keySet()) { + try { + int code = openingToCode.get(opening); + BitSet bitVector = convertIntToBitVector(code); + openingTrie.put(opening, bitVector); + } catch (IllegalArgumentException e) { + } + } + return openingTrie; + } + + private BitSet convertIntToBitVector(int i) throws IllegalArgumentException { + if (i > (1 << bitVectorLength) - 1) { + String errorMessage = String.format("The integer %d is too large to fit into %d bits", i, bitVectorLength); + throw new IllegalArgumentException(errorMessage); + } + BitSet bitVector = new BitSet(); + int index = 0; + for (int j = bitVectorLength - 1; j >= 0; j--) { + boolean jThBit = ((i >> j) & 1) == 1; + bitVector.set(index, jThBit); + } + return bitVector; + } +} diff --git a/src/test/scala/OpeningTrieTest.scala b/src/test/scala/OpeningTrieTest.scala new file mode 100644 index 0000000..49e2cad --- /dev/null +++ b/src/test/scala/OpeningTrieTest.scala @@ -0,0 +1,19 @@ +package org.lichess.compression.game + +import org.specs2.mutable.* + +import scala.jdk.CollectionConverters.* + +class OpeningTrieTest extends Specification: + "opening trie" should: + "find longest common opening" in: + val openingToCode: Map[String, Integer] = Map( + "e4 c5" -> 0, + "d4 d5" -> 1, + "d4 Sf6" -> 2) + val bitVectorLength = 3 + val openingTrie = OpeningTrie(openingToCode.asJava, bitVectorLength) + val pgnMoves = "d4 Sf6 c4".split(" ") + val longestCommonOpening = openingTrie.findLongestCommonOpening(pgnMoves) + val expectedLongestCommonOpening = "d4 Sf6" + longestCommonOpening.get() must_== expectedLongestCommonOpening From 7aeca78eb9ec1536bbcb695c695149d588b96e02 Mon Sep 17 00:00:00 2001 From: ErdoganSeref Date: Tue, 23 Jul 2024 14:02:34 +0200 Subject: [PATCH 2/9] Prepare integration with helper data structure Make encode and decode method non static --- src/main/java/game/Encoder.java | 4 +- src/test/scala/HuffmanPgnTest.scala | 74 +++++++++++++++++------------ 2 files changed, 45 insertions(+), 33 deletions(-) diff --git a/src/main/java/game/Encoder.java b/src/main/java/game/Encoder.java index d68580f..398f8fe 100644 --- a/src/main/java/game/Encoder.java +++ b/src/main/java/game/Encoder.java @@ -35,7 +35,7 @@ private static Role charToRole(char c) { } } - public static byte[] encode(String pgnMoves[]) { + public byte[] encode(String pgnMoves[]) { BitWriter writer = new BitWriter(); Board board = new Board(); @@ -114,7 +114,7 @@ public DecodeResult(String pgnMoves[], Board board, int halfMoveClock, byte posi } } - public static DecodeResult decode(byte input[], int plies) { + public DecodeResult decode(byte input[], int plies) { BitReader reader = new BitReader(input); String output[] = new String[plies]; diff --git a/src/test/scala/HuffmanPgnTest.scala b/src/test/scala/HuffmanPgnTest.scala index 0033442..865f1f5 100644 --- a/src/test/scala/HuffmanPgnTest.scala +++ b/src/test/scala/HuffmanPgnTest.scala @@ -14,99 +14,108 @@ class HuffmanPgnTest extends Specification: "compress and decompress" in: forall(fixtures) { pgn => val pgnMoves = pgn.split(" ") - val encoded = Encoder.encode(pgnMoves) - val decoded = Encoder.decode(encoded, pgnMoves.size) + val encoder = Encoder() + val encoded = encoder.encode(pgnMoves) + val decoded = encoder.decode(encoded, pgnMoves.size) pgnMoves must_== decoded.pgnMoves } "stable format" in: forall(v1 zip fixtures) { case (encoded, pgn) => val pgnMoves = pgn.split(" ") - val decoded = Encoder.decode(base64ToBytes(encoded), pgnMoves.size) + val encoder = Encoder() + val decoded = encoder.decode(base64ToBytes(encoded), pgnMoves.size) pgnMoves must_== decoded.pgnMoves } "least surprise" in: val n = 22 - val decoded = Encoder.decode(Array.fill(n)(0.toByte), n) + val encoder = Encoder() + val decoded = encoder.decode(Array.fill(n)(0.toByte), n) decoded.pgnMoves.mkString(" ") must_== "e4 e5 Nf3 Nf6 Nxe5 Nxe4 Nxf7 Kxf7 d4 Nxf2 Kxf2 d5 Nc3 Nc6 Nxd5 Qxd5 Kg1 Nxd4 Qxd4 Qxd4+ Be3 Qxe3#" "unmoved rooks" in: import scala.jdk.CollectionConverters.* val pgnMoves = "d4 h5 c4 Rh6 Nf3 Rh8".split(" ") - val encoded = Encoder.encode(pgnMoves) + val encoder = Encoder() + val encoded = encoder.encode(pgnMoves) - val d1 = Encoder.decode(encoded, 0) + val d1 = encoder.decode(encoded, 0) Bitboard.squareSet(d1.board.castlingRights).asScala must_== Set(0, 7, 56, 63) - val d2 = Encoder.decode(encoded, pgnMoves.size) + val d2 = encoder.decode(encoded, pgnMoves.size) Bitboard.squareSet(d2.board.castlingRights).asScala must_== Set(0, 7, 56) "half-move clock" in: val pgnMoves = "e4 e5 Nf3 Nc6 Nc3 Nf6 Bb5 d6 O-O Be7 d4 exd4 Nxd4 Bd7 Bg5 O-O Nxc6 bxc6 Bd3 h6 Bh4 Ne8 Bxe7 Qxe7 Qf3 Nf6 Rfe1 Rfe8".split(" ") - val encoded = Encoder.encode(pgnMoves) + val encoder = Encoder() + val encoded = encoder.encode(pgnMoves) val halfMoveClocks = List(0, 0, 0, 1, 2, 3, 4, 5, 0, 1, 2, 0, 0, 0, 1, 2, 3, 0, 0, 1, 0, 1, 2, 0, 0, 1, 2, 3, 4) - (0 to pgnMoves.size).map(Encoder.decode(encoded, _).halfMoveClock) must_== halfMoveClocks + (0 to pgnMoves.size).map(encoder.decode(encoded, _).halfMoveClock) must_== halfMoveClocks "last uci" in: val pgnMoves = "e4 e5 Nf3 Nc6 Bc4 Nf6 d4 exd4 O-O Bc5 e5 d5 exf6 dxc4 Re1+ Be6 Ng5 Qxf6 Nxe6 Qxe6".split(" ") - val encoded = Encoder.encode(pgnMoves) + val encoder = Encoder() + val encoded = encoder.encode(pgnMoves) - val empty = Encoder.decode(encoded, 0) + val empty = encoder.decode(encoded, 0) Option(empty.lastUci) must_== None - val decoded = Encoder.decode(encoded, pgnMoves.size) + val decoded = encoder.decode(encoded, pgnMoves.size) Option(decoded.lastUci) must_== Some("f6e6") "position hash 1. e4 d5 2. e5 f5 3. Ke2 Kf7" in: val pgnMoves = "e4 d5 e5 f5 Ke2 Kf7".split(" ") - val encoded = Encoder.encode(pgnMoves) + val encoder = Encoder() + val encoded = encoder.encode(pgnMoves) // initial position - val d0 = Encoder.decode(encoded, 0) + val d0 = encoder.decode(encoded, 0) d0.positionHashes must_== hexToBytes("463b96") // 1. e4 - val d1 = Encoder.decode(encoded, 1) + val d1 = encoder.decode(encoded, 1) d1.positionHashes must_== hexToBytes("823c9b") // 1. e4 d5 - val d2 = Encoder.decode(encoded, 2) + val d2 = encoder.decode(encoded, 2) d2.positionHashes must_== hexToBytes("0756b9") // 1. e4 d5 2. e5 - val d3 = Encoder.decode(encoded, 3) + val d3 = encoder.decode(encoded, 3) d3.positionHashes must_== hexToBytes("662faf") // 1. e4 d5 2. e5 f5 (en passant matters) - val d4 = Encoder.decode(encoded, 4) + val d4 = encoder.decode(encoded, 4) d4.positionHashes must_== hexToBytes("22a48b") // 1. e4 d5 2. e5 f5 3. Ke2 - val d5 = Encoder.decode(encoded, 5) + val d5 = encoder.decode(encoded, 5) d5.positionHashes must_== hexToBytes("652a60" + "22a48b") // 1. e4 d5 2. e5 f5 3. Ke2 Kf7 - val d6 = Encoder.decode(encoded, 6) + val d6 = encoder.decode(encoded, 6) d6.positionHashes must_== hexToBytes("00fdd3" + "652a60" + "22a48b") "position hash 1. a4 b5 2. h4 b4 3. c4 bxc3 4. Ra3" in: val pgnMoves = "a4 b5 h4 b4 c4 bxc3 Ra3".split(" ") - val encoded = Encoder.encode(pgnMoves) + val encoder = Encoder() + val encoded = encoder.encode(pgnMoves) // 1. a4 b5 2. h4 b4 3. c4 - val d5 = Encoder.decode(encoded, 5) + val d5 = encoder.decode(encoded, 5) d5.positionHashes must_== hexToBytes("3c8123") // 1. a4 b5 2. h4 b4 3. c4 bxc3 4. Ra3 - val d7 = Encoder.decode(encoded, 7) + val d7 = encoder.decode(encoded, 7) d7.positionHashes must_== hexToBytes("5c3f9b" + "93d326") "position hash threefold" in: // https://lichess.org/V0m3eSGN val pgnMoves = "Nf3 d5 d4 c5 dxc5 e6 c4 Bxc5 Nc3 Nf6 e3 O-O cxd5 Nxd5 Nxd5 Qxd5 Qxd5 exd5 Be2 Nc6 a3 Bf5 b4 Bb6 Bb2 Rfd8 Rd1 Rac8 O-O Ne7 Nd4 Bg6 Rc1 Rxc1 Rxc1 Nf5 Bf3 Kf8 Nb3 Nxe3 Bd4 Nc2 Bxb6 axb6 Bd1 Re8 Bxc2 Bxc2 Nd4 Bd3 f3 Bc4 Kf2 Re5 g4 g6 Rc3 Ke7 Re3 Kf6 h4 Rxe3 Kxe3 Ke5 f4+ Kd6 g5 Ke7 Nf3 Ke6 Nd4+ Ke7 Nf3 Ke6 Nd4+ Ke7".split(" ") - val encoded = Encoder.encode(pgnMoves) - val decoded = Encoder.decode(encoded, pgnMoves.size) + val encoder = Encoder() + val encoded = encoder.encode(pgnMoves) + val decoded = encoder.decode(encoded, pgnMoves.size) val threefold = "966379" val ncheck = "65afff" @@ -118,8 +127,9 @@ class HuffmanPgnTest extends Specification: "position hash compat" in: // https://lichess.org/DoqH1EQP val pgnMoves = "e4 c5 Nf3 d6 d4 cxd4 Nxd4 Nc6 Nc3 g6 Be3 Bg7 Bc4 Nf6 f3 O-O Qd2 Nd7 O-O-O a5 g4 Nce5 Be2 a4 a3 Nb6 h4 Nbc4 Bxc4 Nxc4 Qf2 Qb6 b3 Nxe3 Qxe3 e5 Nf5 Qxe3+ Nxe3 axb3 cxb3 Rxa3 Kb2 Ra6 h5 h6 hxg6 fxg6 Ned5 Rxf3 Ne7+ Kf7 Nxc8 Ke6 Nxd6 Rf2+ Kb1 Rxd6 Nd5 Rc6 Rc1 Rxc1+ Rxc1 Re2 Rc7 Rxe4 Nb6 Bf8 Rxb7 Rb4 Rb8 Rxb3+ Kc2 Rb5 Rxf8 Rxb6 Rg8 Kf6 Rf8+ Kg5 Rh8 Rd6 Re8 Kxg4 Rxe5 g5 Re3 Kf5".split(" ") - val encoded = Encoder.encode(pgnMoves) - val decoded = Encoder.decode(encoded, pgnMoves.size) + val encoder = Encoder() + val encoded = encoder.encode(pgnMoves) + val decoded = encoder.decode(encoded, pgnMoves.size) decoded.positionHashes must_== base64ToBytes("oB9I1h1e6YDy") "work with all black legal moves in YycayYfM" in: @@ -128,8 +138,9 @@ class HuffmanPgnTest extends Specification: val legals = "Kh8 Kf8 Kg7 Kf7 Rf8 Re8 Rd8 Rb8 Ra8 R8c7 R8c6 R5c7 R5c6 Rh5 Rg5 Rf5 Re5+ Rd5 Rb5 Ra5 Rc4 h6 f5 e5 h5".split(" ") forall(legals) { legal => val pgnMoves = (prefix + " " + legal).split(" ") - val encoded = Encoder.encode(pgnMoves) - val decoded = Encoder.decode(encoded, pgnMoves.size) + val encoder = Encoder() + val encoded = encoder.encode(pgnMoves) + val decoded = encoder.decode(encoded, pgnMoves.size) pgnMoves must_== decoded.pgnMoves } @@ -137,8 +148,9 @@ class HuffmanPgnTest extends Specification: // Exclude compression as cause of https://github.com/ornicar/lila/issues/5594 val prefix = "c4 e5 g3 h5 Nc3 h4 Bg2 Nf6 d3 Bb4 Bd2 d6 Nf3 h3 Bf1 Nc6 e3 Bg4 Be2 d5 Nxd5 Nxd5 cxd5 Qxd5 Bxb4 Nxb4 Qa4+ c6 Qxb4 Bxf3 Bxf3 Qxf3 Rg1 O-O-O Qe4 Qf6 O-O-O Rd5 f4 Rhd8 Rgf1 Qe6 Kb1 f5 Qc4 e4 d4 Kb8 Rc1 Qe7 Rg1 Qd7 Qc2 Re8 Qe2 Ra5 g4 g6 gxf5 gxf5 Qh5 Rd8 Qh6 c5 Rg7 Qa4 a3 Qb3 Qf6 Rc8 Qd6+ Ka8" val pgnMoves = s"$prefix Rxc5 Raxc5".split(" ") - val encoded = Encoder.encode(pgnMoves) - val decoded = Encoder.decode(encoded, pgnMoves.size) + val encoder = Encoder() + val encoded = encoder.encode(pgnMoves) + val decoded = encoder.decode(encoded, pgnMoves.size) pgnMoves must_== decoded.pgnMoves "pass perft test" in: From b172b7c5aacc706efd92ea4fa87a7800548db2f9 Mon Sep 17 00:00:00 2001 From: ErdoganSeref Date: Tue, 23 Jul 2024 15:03:57 +0200 Subject: [PATCH 3/9] Calculate bit vector length instead of passing parameter --- src/main/java/game/OpeningTrie.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/game/OpeningTrie.java b/src/main/java/game/OpeningTrie.java index 4ad95be..a22c4ae 100644 --- a/src/main/java/game/OpeningTrie.java +++ b/src/main/java/game/OpeningTrie.java @@ -10,9 +10,9 @@ public class OpeningTrie { private final int maxOpeningPlies; private final Trie openingTrie; - public OpeningTrie(Map openingToCode, int bitVectorLength) { + public OpeningTrie(Map openingToCode) { this.maxOpeningPlies = getMaxOpeningPlies(openingToCode); - this.bitVectorLength = bitVectorLength; + this.bitVectorLength = getLowestSufficientBitVectorLength(openingToCode.values().toArray(Integer[]::new)); this.openingTrie = buildOpeningTrie(openingToCode); } @@ -63,6 +63,11 @@ private int getMaxOpeningPlies(Map openingToCode) { .orElse(0); } + private int getLowestSufficientBitVectorLength(Integer integers[]) { + int max = Arrays.stream(integers).max(Integer::compare).orElse(0); + return (31 - Integer.numberOfLeadingZeros(max)) + 1; + } + private Trie buildOpeningTrie(Map openingToCode) { Trie openingTrie = new PatriciaTrie<>(); for (String opening : openingToCode.keySet()) { From 879a31774d531cf3c20bfda2096ad81c9a9b85e0 Mon Sep 17 00:00:00 2001 From: ErdoganSeref Date: Thu, 25 Jul 2024 18:56:32 +0200 Subject: [PATCH 4/9] Construct opening trie from most common openings --- src/main/java/game/OpeningTrie.java | 24 + .../game/most_common_opening_moves_sorted.txt | 1900 +++++++++++++++++ src/test/scala/OpeningTrieTest.scala | 2 +- 3 files changed, 1925 insertions(+), 1 deletion(-) create mode 100644 src/main/java/game/most_common_opening_moves_sorted.txt diff --git a/src/main/java/game/OpeningTrie.java b/src/main/java/game/OpeningTrie.java index a22c4ae..31e716a 100644 --- a/src/main/java/game/OpeningTrie.java +++ b/src/main/java/game/OpeningTrie.java @@ -3,6 +3,9 @@ import org.apache.commons.collections4.Trie; import org.apache.commons.collections4.trie.PatriciaTrie; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.*; public class OpeningTrie { @@ -16,6 +19,11 @@ public OpeningTrie(Map openingToCode) { this.openingTrie = buildOpeningTrie(openingToCode); } + public static OpeningTrie mostCommonOpenings() { + Map mostCommonOpeningToCode = getMostCommonOpeningToCode(); + return new OpeningTrie(mostCommonOpeningToCode); + } + public BitSet get(String opening) { return openingTrie.get(opening); } @@ -94,4 +102,20 @@ private BitSet convertIntToBitVector(int i) throws IllegalArgumentException { } return bitVector; } + + private static Map getMostCommonOpeningToCode() { + try { + Path filepath = Path.of("src/main/java/game/most_common_opening_moves_sorted.txt"); + List mostCommonOpenings = Files.readAllLines(filepath); + Map mostCommonOpeningToCode = new HashMap<>(); + int i = 0; + for (String opening: mostCommonOpenings) { + mostCommonOpeningToCode.put(opening, i); + i++; + } + return mostCommonOpeningToCode; + } catch (IOException e) { + throw new RuntimeException(e); + } + } } diff --git a/src/main/java/game/most_common_opening_moves_sorted.txt b/src/main/java/game/most_common_opening_moves_sorted.txt new file mode 100644 index 0000000..2731ee4 --- /dev/null +++ b/src/main/java/game/most_common_opening_moves_sorted.txt @@ -0,0 +1,1900 @@ +e4 e6 Nf3 +e4 e5 Nf3 Nc6 Bb5 +e4 e5 Bc4 +e4 c5 Bc4 +d4 d5 Bf4 +d4 d5 c4 e6 +e4 e5 Nf3 d6 Bc4 +d4 d5 e3 +e4 e5 Nf3 d6 d4 +e4 e5 Bc4 Nf6 +e4 e5 Nf3 Nc6 d4 exd4 Nxd4 +e4 c5 Nf3 d6 d4 cxd4 +e4 e5 Nf3 d6 +e4 c5 Nc3 +d4 d5 c4 Nf6 +e4 d5 exd5 Qxd5 Nc3 Qd8 +e4 e5 d4 +e4 e5 Qh5 +e4 g6 d4 Bg7 +d4 d5 c4 dxc4 +e4 e5 Nf3 Nc6 Bc4 h6 +d4 d5 c4 c6 Nc3 +e4 e6 d4 d5 exd5 +e4 d5 Nf3 +e4 c5 c3 +e4 e5 d4 exd4 Qxd4 +e4 e5 Nf3 Nf6 Nc3 +e4 e5 Nf3 Bc5 +d4 d5 Nc3 +d4 d5 c4 dxc4 e3 +e4 e5 Nf3 Nc6 d4 +d4 d5 c4 c6 +d4 d5 Nf3 Nc6 +d4 d6 c4 +e4 e5 Nf3 Nc6 Nc3 +e4 e6 f4 +e4 e6 d4 d5 +e4 e6 e5 +e4 e5 d4 exd4 c3 +e4 c5 d4 cxd4 c3 +e4 e5 Qf3 +e4 c6 d4 d5 e5 +Nf3 d5 g3 +e4 e5 Nf3 d5 +e4 c5 Nf3 Nc6 Bb5 +e4 c6 d4 d5 Nc3 dxe4 +d4 d5 Bg5 +e4 e5 Bc4 Bc5 +d4 Nf6 Nf3 g6 +e4 c6 d4 d5 exd5 +e4 c6 Bc4 +d4 d5 c4 +e4 e5 Nf3 Nc6 Bc4 d6 +e4 c5 Nc3 e6 +d4 d5 c4 e5 +d4 d5 e3 Nf6 +e4 e5 Nf3 Nc6 Nc3 Nf6 +e4 e6 d4 d5 e5 c5 c3 Nc6 +e4 e5 Nf3 f6 +e4 e5 Nf3 Nc6 d4 exd4 +d4 c5 dxc5 +e4 c6 d4 +e4 e5 Nf3 Nc6 Bc4 Bc5 d3 +e4 c6 Nc3 d5 +e4 e5 Nf3 Nc6 Bc4 Nf6 Nc3 +e4 e5 Nf3 Nc6 Bb5 a6 Bxc6 +d4 f5 c4 +e4 e5 c3 +e4 e5 Nf3 Nc6 Bb5 Nd4 +e4 e5 Nf3 d6 Bc4 Be7 +e4 Nf6 Nc3 d5 +e4 e5 Nf3 Nc6 c3 +e4 e5 Nf3 Nc6 Bb5 Nge7 +d4 Nf6 c4 e6 Nc3 Bb4 +e4 c5 Nf3 d6 Bb5+ +e4 e5 Nf3 Nc6 Bc4 Nd4 +d4 d5 e4 +e4 e5 Nf3 Nf6 Nxe5 +e4 e5 Nf3 Nc6 Bc4 Nf6 d3 Bc5 +d4 Nf6 Bg5 +d4 d5 c4 Bf5 +c4 c5 Nc3 Nc6 +d4 c5 d5 d6 +e4 e6 d4 d5 e5 c5 Nf3 +d4 d5 c4 c6 cxd5 +e4 e5 c4 +d4 d5 f4 +e4 e6 d4 d5 e5 c5 c3 +e4 c5 Nf3 e6 d4 cxd4 Nxd4 a6 Nc3 +e4 e6 d4 d5 e5 +c4 c5 Nc3 +e4 Nc6 d4 e5 d5 +d4 Nf6 c4 c5 +b3 e5 Bb2 Nc6 +c4 Nf6 Nc3 e6 +d4 Nf6 c4 d6 +d4 d5 Nf3 Nf6 Bf4 +e4 c6 d4 d5 e5 Bf5 Nf3 +e4 e5 f4 exf4 Nf3 d6 +d4 d5 Nc3 e6 +e4 e5 Qh5 Nf6 +e4 c5 Nc3 Nc6 f4 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 b5 +e4 e5 Nf3 Nc6 c3 Nf6 +d4 e5 e3 +e4 e6 d4 d5 exd5 exd5 c4 +d4 Nf6 c4 e5 +e4 Nf6 d3 +e4 Nf6 e5 Nd5 d4 +e4 c5 Nf3 e6 d4 cxd4 Nxd4 a6 +e4 c6 d3 +e4 e5 f3 +e4 e6 Nf3 d5 Nc3 +e4 e5 Nf3 Nf6 Nxe5 Nxe4 +e4 c5 Nf3 e6 d4 cxd4 Nxd4 Nc6 +d4 e6 c4 b6 +e4 c5 Nf3 Nc6 d4 cxd4 Nxd4 g6 Nc3 +g3 d5 Bg2 c6 +e4 c5 b4 +e4 c5 d4 cxd4 Nf3 +e4 Nc6 d4 +e4 e5 Nc3 Bc5 +d4 d5 Nf3 e6 Bf4 +e4 e5 Nf3 Nc6 Nc3 Nf6 d4 exd4 +e4 e5 d4 exd4 Nf3 +e4 e5 Nf3 Nc6 Bc4 Bc5 c3 Nf6 d4 +d4 e5 d5 +e4 e5 Bc4 Nf6 d4 +d4 e5 Nf3 +d4 Nf6 Nf3 g6 Bf4 +e4 d6 d4 Nd7 +g3 d5 Bg2 e6 +b3 e5 Bb2 Nc6 e3 +d4 c5 d5 Nf6 +e4 e5 Nf3 d5 exd5 e4 +e4 e5 Nf3 f5 exf5 +e4 d6 d4 e5 +d4 d5 c4 e6 Nc3 Nf6 Bg5 Be7 +e4 e5 Nf3 Nc6 Nc3 Bb4 +e4 e5 f4 Bc5 +d4 e5 dxe5 d6 +e4 e5 b3 +e4 e5 f4 exf4 Nf3 Be7 +e4 d5 exd5 Nf6 c4 c6 +d4 Nf6 c4 g6 Nc3 d5 +e4 e6 d4 Nf6 +d4 Nf6 c4 e5 dxe5 Ng4 Nf3 +e4 c6 d4 d5 exd5 cxd5 c4 +e4 e5 Nf3 Qe7 +d4 d5 Nf3 Nf6 g3 +d4 Nf6 Nf3 d6 +e4 e6 d4 d5 Nc3 dxe4 +e4 e5 Nf3 Nc6 Bb5 a6 Bxc6 bxc6 +Nf3 d5 d3 +e4 e5 Nf3 Nc6 Bc4 Bc5 Nc3 Nf6 +e4 e6 d4 d5 e5 c5 +d4 Nf6 Nf3 g6 g3 +e4 d5 exd5 c6 dxc6 Nxc6 +Nf3 d5 Nc3 +e4 e5 d4 d5 +d4 Nf6 Nf3 e6 Bf4 +e4 e5 Nf3 f5 +e4 e6 d4 c5 d5 +e4 c5 Nf3 d6 d4 +e4 d5 exd5 Nf6 c4 e6 +d4 d5 Nf3 Nf6 e3 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 Nf6 d3 +e4 c5 Nf3 d6 d4 cxd4 Qxd4 +e4 e5 f4 exf4 Nf3 g5 +e4 Nc6 d4 d5 e5 +e4 e5 f4 d5 exd5 +e4 e5 Nf3 Nc6 Bc4 Bc5 b4 +e4 c5 Nf3 Nc6 d4 cxd4 Nxd4 e5 Nb5 d6 +e4 e5 f4 exf4 Nf3 Nf6 +d4 Nf6 f4 +d4 c5 d5 e5 +e4 d6 d4 Nf6 Nc3 g6 +d4 d5 e3 Nf6 Bd3 +e4 c6 c4 d5 +e4 c5 g3 +e4 e5 Nf3 Nc6 d4 exd4 c3 +Nf3 d5 c4 +d4 d6 c4 e5 +e4 c5 Nf3 d6 d4 cxd4 Nxd4 Nf6 Nc3 g6 +b4 e5 Bb2 d6 +Nf3 d5 b3 +e4 e5 Nf3 Nc6 Bc4 Nf6 d3 Be7 +e4 e6 d4 d5 Nc3 Nf6 e5 +d4 c6 c4 d6 +e4 c6 d4 d5 e5 c5 +e4 e5 Nf3 Nc6 Nc3 Nf6 Bb5 +e4 Nf6 Bc4 +e4 c5 Nf3 a6 d4 +d4 Nf6 Bg5 e6 +e4 e5 d4 exd4 c3 dxc3 Bc4 cxb2 Bxb2 +d4 Nf6 c4 e6 Nc3 Bb4 Bg5 +e4 e5 Nf3 Nf6 d4 +e4 e5 Nf3 Nc6 Be2 +e4 c6 d4 d5 +e4 c5 Nf3 Nc6 Bb5 g6 +e4 Nf6 e5 Nd5 d4 d6 +d4 Nf6 c4 c6 +d4 d5 Nf3 Nf6 Bg5 +g4 d5 Bg2 Bxg4 c4 +e4 c6 d4 d5 Nc3 +e4 e5 Nf3 Nc6 Bc4 Bc5 c3 Nf6 d3 +d4 d5 Bf4 c5 +d4 Nf6 Nf3 e6 e3 +d4 d5 c4 Nc6 +d4 d5 Qd3 +e4 c5 a3 +d4 Nf6 c4 e6 Nc3 Bb4 Qc2 +e4 c6 Nc3 +d4 Nf6 d5 +e4 c5 Nf3 d6 d4 cxd4 Nxd4 Nf6 Nc3 a6 Bg5 +e4 c5 Nf3 d6 d4 cxd4 c3 +e4 e5 a3 +d4 Nf6 e4 +e4 e5 Nf3 Nc6 g3 +e4 e5 d4 exd4 Bc4 +e4 c5 Nf3 d6 d4 cxd4 Nxd4 Nf6 Nc3 Nc6 +d4 d5 c4 dxc4 e4 b5 +c4 e5 Nc3 Nf6 g3 +e4 Nc6 Nf3 f5 exf5 +e4 c5 Nf3 e6 d4 d5 +e4 e5 Nf3 d6 d4 Nd7 +e4 e6 d4 d5 e5 c5 c3 Nc6 Nf3 Bd7 +d4 Nf6 g3 +d4 d5 c4 dxc4 Qa4+ +d4 e5 dxe5 f6 +d4 e5 dxe5 Nc6 Nf3 Qe7 +e4 e6 d4 a6 +e4 e5 Nf3 c6 +e4 e5 Nf3 Nc6 Bc4 Nf6 Ng5 Bc5 +e4 c5 Nf3 Nc6 d4 e6 +e4 e5 Nf3 d6 d4 Nf6 dxe5 +g4 d5 Bg2 +c4 e5 Nc3 Bb4 +e4 c5 c3 d5 exd5 Qxd5 +e4 d6 d4 Nf6 Nc3 g6 Nf3 Bg7 +e4 e5 Bb5 +e4 e5 Nf3 Nf6 Nxe5 d6 Nf3 Nxe4 d4 +e4 e6 b3 +e4 Nf6 e5 Nd5 d4 d6 c4 Nb6 exd6 +e4 e5 Nc3 Nc6 f4 +c4 e5 Nf3 +Nf3 Nf6 g3 d5 +e4 Nc6 Nf3 e6 +e4 e5 Nf3 Nc6 Bb5 f6 +d4 Nf6 c4 c5 d5 b5 cxb5 a6 +Nf3 Nf6 e3 +e4 g6 d4 Bg7 f4 +d4 d5 Nc3 Bf5 +e4 e6 Qe2 +e4 e5 d4 exd4 c3 dxc3 Bc4 cxb2 Bxb2 Bb4+ +Nf3 Nf6 b3 +e4 c5 Nf3 b6 +e4 e5 Bd3 +d4 d5 c4 dxc4 e4 e5 +e4 c5 Nf3 e6 c4 +e4 Nf6 e5 Ne4 +e4 e5 Nf3 Nc6 Bb5 a6 Bxc6 dxc6 O-O Bd6 +e4 e5 f4 Nf6 +e4 c5 Nf3 Nc6 d4 cxd4 Nxd4 g6 Nxc6 +e4 d6 d4 Nf6 Nc3 c6 +e4 e5 d4 exd4 Qxd4 Nc6 Qe3 Nf6 +e4 e5 f4 exf4 Bc4 +d4 d5 Nc3 e6 Bf4 +e4 Nc6 Nf3 f5 +e4 c5 Nf3 d6 d4 cxd4 Nxd4 g6 +d4 Nf6 c4 c5 d5 e6 +e4 c5 Nf3 Nc6 d4 cxd4 Nxd4 Nf6 Nc3 e5 +e4 e6 d4 d5 e5 c5 c3 Nc6 Nf3 Qb6 Bd3 +d4 f5 c4 e6 Nc3 +e4 c5 Nc3 e6 g3 +e4 c5 Nf3 Nc6 d4 cxd4 Nxd4 g6 +e4 c6 d4 d5 f3 +e4 c5 Nf3 e6 d4 cxd4 Nxd4 a6 Nc3 b5 +e4 Nf6 e5 Ng8 +Nf3 d5 c4 d4 +e4 e6 d4 d5 Bd3 +e4 e5 Nf3 Nc6 Nc3 Nf6 Nxe5 +e4 e5 Nf3 Nc6 Bc4 Nf6 d4 exd4 +e4 e5 Nf3 Nc6 Bc4 Bc5 d4 +d4 Nf6 c4 e6 Nc3 d5 cxd5 +e4 c5 Nf3 e6 d4 cxd4 Nxd4 Nf6 Nc3 Bb4 +d4 Nf6 c4 Nc6 +d4 d5 c4 c6 Nc3 dxc4 +e4 e5 Nf3 Nc6 d4 exd4 Nxd4 Bc5 Nxc6 Qf6 +Nf3 d5 d4 Bg4 +e4 c5 Nf3 d6 d4 cxd4 Nxd4 Nf6 Nc3 g6 Be3 Bg7 f3 O-O +e4 c5 Nf3 d6 d4 cxd4 Nxd4 Nf6 Nc3 a6 Bg5 e6 +d4 e6 e4 d6 +d4 d5 c4 dxc4 e4 Nf6 +e4 e5 f4 d5 Nf3 +e4 e5 Nf3 Nf6 d4 exd4 +c4 e5 Nc3 Nc6 Nf3 +e4 Nc6 Nf3 d6 +e4 e5 Nf3 Nc6 Nc3 Nf6 d4 +d4 Nf6 Bg5 e6 e4 +g3 d5 Bg2 c5 +e4 e5 Nf3 Nc6 Bc4 Be7 d4 exd4 +d4 Nf6 c4 e6 Bg5 +c4 d5 cxd5 Qxd5 Nc3 Qa5 +d4 d5 c4 e6 Nc3 Nf6 Bf4 +e4 c6 d4 d5 e5 Bf5 g4 +d4 Nf6 c4 g6 Nc3 Bg7 e4 d6 f3 +e4 e5 Nf3 Nf6 Nxe5 d6 Nf3 Nxe4 Qe2 +e4 e5 Bc4 d5 +e4 c6 d4 d5 e5 Bf5 Nc3 +d4 d5 Nc3 Nf6 Bf4 +e4 e5 Nf3 d6 Bc4 f5 +e4 c5 Nf3 d6 d4 cxd4 Nxd4 Nf6 f3 +Nf3 d5 c4 dxc4 +d4 Nf6 c4 e5 dxe5 Ng4 Bf4 +e4 e5 Nf3 Nc6 Bc4 Nf6 Ng5 d5 exd5 Nd4 +d4 d5 c4 Nc6 Nc3 +d4 g6 c4 Bg7 Nc3 d6 e4 +e4 c5 Nf3 e6 d4 cxd4 c3 +e4 Nc6 d4 d5 exd5 Qxd5 +e4 c5 b4 cxb4 a3 bxa3 +e4 e6 d4 d5 Nd2 Nf6 e5 Nfd7 Bd3 c5 c3 Nc6 +e4 c5 Nf3 Nf6 +e4 c5 Nf3 d6 d4 cxd4 Nxd4 Nf6 Nc3 a6 Bg5 e6 f4 Be7 +e4 e6 d4 d5 Nd2 c5 c3 +d4 Nf6 c4 g6 Nc3 d5 cxd5 Nxd5 +e4 e5 Nf3 Nf6 Nxe5 d6 Nf3 Nxe4 Nc3 +d4 Nf6 c4 c5 d5 e6 Nc3 exd5 cxd5 d6 e4 +e4 e5 Nf3 Nc6 d4 Nxd4 +d4 g6 c4 Bg7 Nc3 d6 +c4 Nf6 Nc3 d5 +d4 Nf6 c4 e5 dxe5 Ng4 +d4 f5 Bg5 +e4 c6 d4 d5 e5 Bf5 h4 +e4 Nc6 Bb5 +e4 e6 d4 d5 Nc3 Bb4 exd5 +e4 e6 g3 +h3 e5 a3 +e4 c5 Nf3 d6 d4 cxd4 Nxd4 Nf6 Nc3 g6 Be2 +e4 c5 Nf3 d6 d4 Nf6 +e4 e5 Nf3 Nc6 Bc4 f5 +e4 c5 Ne2 +e4 c5 Nf3 Nf6 e5 +d4 d5 c4 Nc6 cxd5 Qxd5 +e4 d6 d4 Nf6 Nc3 g6 Bg5 +e4 e5 Nc3 Nc6 g3 +d4 Nf6 Bg5 Ne4 Bh4 +d4 Nf6 c4 c5 d5 b5 +e4 Nf6 e5 Nd5 d4 d6 Nf3 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 Nf6 O-O Be7 Re1 b5 Bb3 +e4 Nc6 d4 e5 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 d6 +e4 c5 Nf3 Nf6 Nc3 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 Bc5 +e4 e5 Nf3 Nc6 Bc4 Bc5 O-O Nf6 c3 +e4 e5 d4 exd4 c3 d5 +c4 c5 Nf3 +Nf3 d5 g3 c5 +e4 e5 Nf3 d6 Bc4 Be7 c3 +Nf3 d5 g3 Bg4 +e4 c5 d4 cxd4 c3 Nf6 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 b5 Bb3 Bc5 +e4 c6 d4 d5 Nc3 Nf6 +e4 e6 d4 d5 Nc3 Nf6 Bg5 Be7 e5 Nfd7 Bxe7 Qxe7 +e4 c5 Nf3 e6 b3 +e4 d5 Nc3 dxe4 Nxe4 e5 +e4 e6 d4 d5 Nc3 dxe4 Nxe4 Nd7 +e4 c6 d4 d5 Nd2 dxe4 Nxe4 Bf5 +e4 g6 d4 Bg7 Bc4 +d4 e6 c4 BbNc3 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 Nf6 Nc3 +e4 e5 Nf3 Nc6 Bb5 f5 +e4 c6 d4 d5 exd5 cxd5 Nf3 Nc6 +c4 d5 cxd5 Nf6 +Nf3 d5 g3 c5 Bg2 Nc6 +d4 Nf6 Nc3 d5 e4 +e4 c5 f4 d5 exd5 Nf6 +e4 Nc6 d4 d6 +e4 e5 f4 exf4 Nf3 h6 +e4 c6 d4 d5 exd5 cxd5 c4 Nf6 Nc3 e6 +d4 d5 c4 Nc6 Nc3 dxc4 +e4 d6 d4 Nf6 Nc3 g6 f4 +d4 d5 c4 dxc4 e4 Nc6 +e4 d5 exd5 Nf6 d4 Bg4 Be2 +e4 e5 Nf3 f5 Nc3 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 Nf6 O-O Be7 Re1 b5 Bb3 O-O +d4 e6 c4 Bb4+ +e4 e6 d4 d5 Nd2 c5 exd5 exd5 +e4 e5 Nf3 Nc6 d4 exd4 Bc4 Nf6 e5 +d4 d5 c4 dxc4 Nf3 Nf6 +d4 d5 Nc3 c5 +d4 d5 c4 c6 Nf3 Nf6 e3 +e4 c5 Nf3 a6 +e4 c5 Nf3 e6 d4 cxd4 Nxd4 Bc5 +f4 e5 fxe5 d6 exd6 Bxd6 Nf3 g5 +d4 Nf6 c4 b6 +e4 g6 d4 Bg7 Nf3 b6 +c4 e5 Nc3 d6 Nf3 +d4 d5 Nc3 Nf6 Bf4 e6 +e4 e6 Nf3 d5 e5 c5 b4 +e4 c5 Nf3 e6 d4 a6 +e4 e5 Ne2 +e4 d5 exd5 Qxd5 Nc3 Qd8 d4 Nf6 Nf3 Bg4 +e4 e6 d4 d5 e5 c5 dxc5 +e4 e6 d4 d5 Nc3 Nf6 Bg5 +e4 e5 Nf3 Nc6 Bc4 Nf6 Ng5 Bc5 Bxf7+ +e4 c5 Nf3 Nc6 d4 cxd4 Nxd4 g6 Nc3 Bg7 Be3 Nf6 Bc4 +d4 Nf6 Nf3 c5 d5 +e4 c5 Nf3 Nc6 d4 cxd4 Nxd4 Qc7 +e4 e6 Bb5 +d4 d5 e4 dxe4 f3 +e4 c5 Nf3 e5 +d4 d5 Nf3 Nf6 e3 e6 Bd3 +e4 e5 f4 d5 exd5 exf4 +h3 d5 a3 e5 +e4 e6 d4 d5 Nc3 Nf6 e5 Nfd7 f4 c5 Nf3 Nc6 Be3 +e4 c5 Nf3 a6 d4 cxd4 Nxd4 e5 +e4 e5 f4 exf4 Nf3 g5 d4 +d4 Nf6 Nc3 c5 +e4 c5 Nf3 e6 d4 cxd4 Nxd4 Nf6 Nc3 Nc6 +e4 d5 exd5 c6 dxc6 e5 +e4 e5 Nf3 Nc6 Bb5 a6 Bxc6 dxc6 Nc3 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 Nf6 O-O Bc5 +e4 e5 d3 f5 +e4 e5 d4 exd4 c3 dxc3 Bc4 cxb2 Bxb2 Nf6 +g3 e5 Nf3 +e4 Nc6 Nc3 e6 +d4 Nf6 c4 e6 Nf3 Bb4+ +e4 c5 Nf3 d6 d4 cxd4 Nxd4 Nf6 Nc3 a6 h3 +e4 e5 f4 f5 +e4 e5 Nf3 d6 d4 exd4 Bc4 +e4 g6 d4 Bg7 Nc3 c5 +e4 d6 d4 Nf6 f3 +e4 Nf6 e5 Nd5 Nc3 +e4 e5 Nf3 Nf6 Nxe5 d6 Nf3 Nxe4 +e4 c5 Nf3 d6 d4 cxd4 Nxd4 Nf6 Nc3 a6 Bg5 e6 f4 +e4 e5 Nf3 Nc6 Bc4 Nf6 Ng5 d5 exd5 b5 +g4 e5 Bg2 d5 c4 +e4 e5 Nf3 Nc6 Bc4 Nf6 d4 exd4 O-O +d4 Nf6 c4 e6 Nc3 Bb4 a3 Bxcbxc3 +b4 Nf6 Bb2 g6 +d4 e5 dxe5 Nc6 Nf3 Bc5 +e4 e5 d4 exd4 Qxd4 Nc6 Qc4 +e4 c6 b3 +e4 c5 Nf3 d6 d4 cxd4 Nxd4 Nf6 Nc3 a6 Be3 Ng4 +g4 d5 Bg2 c6 +e4 e5 Nf3 Nf6 Nxe5 d6 Nf3 +e4 Nf6 e5 Nd5 d4 d6 Bc4 +e4 e5 Nf3 Nc6 Bb5 d5 +e4 c5 Nf3 Nc6 d4 cxd4 Nxd4 Qb6 +e4 e5 f4 exf4 d4 +d4 d5 Nf3 Nf6 e3 e6 +e4 c6 d4 d5 Nd2 dxe4 Nxe4 +e4 Nf6 Bc4 Nxe4 Bxf7+ +d4 Nf6 c4 e6 Nc3 Bb4 f3 +e4 e5 Nf3 Nc6 d4 exd4 Nxd4 Bc5 Nb3 +e4 c5 c3 Nf6 e5 Nd5 d4 cxd4 +d4 c5 c4 cxd4 e3 +d4 d5 e4 dxe4 Nc3 Nf6 f3 exf3 Qxf3 +Nf3 Nf6 Nc3 Nc6 +e4 e5 d4 exd4 Nf3 c5 Bc4 +d4 Nf6 c4 g6 Nc3 Bg7 e4 d6 f3 O-O Be3 e5 +e4 Nf6 e5 Nd5 d4 d6 c4 Nb6 f4 +d4 d5 Nf3 Nf6 e3 Bf5 +e4 c6 c4 +e4 e5 d4 exd4 Nf3 c5 +d4 Nf6 Nf3 c6 +e4 e5 f4 d5 exd5 e4 d3 +e4 e6 d4 d5 Nc3 Bb4 e5 +e4 g6 d4 Bg7 Nc3 d6 f4 +c4 e5 Nc3 Nf6 g3 d5 +e4 c5 Nf3 d6 d4 cxd4 Nxd4 Nf6 Nc3 g6 Be3 +e4 e5 Nf3 Nc6 Bb5 Be7 +e4 e5 Bc4 f5 +e4 e5 Nf3 Nc6 Bb5 a6 Bxc6 dxc6 O-O f6 +e4 e5 f4 Qf6 +e4 e5 Nf3 Nc6 Bc4 Bc5 O-O Nf6 d4 +c4 e5 Nc3 Nf6 Nf3 Nc6 e3 +e4 c5 Nf3 a6 c3 +d4 Nf6 c4 e6 Nc3 Bb4 Qc2 c5 +e4 Nf6 e5 Nd5 d4 d6 Nf3 Nc6 +e4 e5 Nc3 Nf6 g3 +e4 g6 d4 Bg7 Nc3 d6 Nf3 +Nc3 e5 Nf3 Nc6 d4 +e4 e5 f4 exf4 Bc4 Nc6 +d4 d5 c4 e6 Nf3 c5 +d4 e5 dxe5 Nc6 Nf3 f6 +d4 Nf6 c4 c5 d5 b5 cxb5 a6 b6 +e4 e5 Nf3 Nc6 Nc3 g6 +d4 Nc6 c4 e5 d5 Nce7 +d4 d5 c4 dxc4 Nf3 e6 +Nf3 Nf6 e4 +e4 e5 Nf3 Nc6 Nc3 Nf6 Bb5 a6 Bxc6 +e4 e6 d4 d5 Nc3 dxe4 Nxe4 Bd7 Nf3 Bc6 +d4 Nf6 c4 g6 Nc3 d5 Nf3 Bg7 Bg5 +e4 e6 d4 d5 Nd2 c5 Ngf3 +d4 Nf6 c4 g6 Nc3 d5 cxd5 Nxd5 e4 Nxc3 bxc3 Bg7 Bc4 +e4 c5 Nc3 Nc6 g3 g6 Bg2 Bg7 +d4 d5 c4 c6 Nf3 Nf6 Bg5 +e4 c6 d4 d5 e5 Bf5 Ne2 +e4 c5 Nf3 e6 d4 cxd4 Nxd4 Nc6 Nc3 Qc7 +e4 e6 d4 d5 Nd2 Nf6 e5 Nfd7 f4 +e4 e5 f4 d5 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 Nf6 O-O Be7 +e4 e6 d4 d5 e5 c5 c3 Qb6 Nf3 Bd7 +e4 e5 Nf3 Nc6 Bc4 Bc5 c3 d6 d4 exd4 cxd4 Bb6 +e4 e6 Nf3 f5 +e4 c6 d4 d5 Nc3 dxe4 Nxe4 Nf6 Nxfgxf6 +e4 e5 f4 Qhg3 Qe7 +e4 e5 Nf3 Nf6 Nxe5 Nxe4 Qe2 Qe7 +e4 e5 Nf3 Nc6 d4 exd4 Nxd4 Bb4+ +e4 e5 Nf3 Nc6 d4 exd4 Nxd4 Qh4 Nc3 Bb4 +d4 d5 e4 dxe4 Nc3 Bf5 +c4 d5 cxd5 e6 +d3 e5 Nd2 +e4 e6 d4 d5 Nc3 Bb4 a3 +d4 Nf6 c4 c5 d5 e5 +c4 e6 Nf3 d5 +d4 Nf6 c4 e6 Nf3 BbBd2 Qe7 +c4 e6 Nf3 +b4 e5 a3 +e4 e5 Nc3 d6 f4 +c4 e5 Nf3 e4 +e4 e6 d4 d5 Nc3 Nf6 e5 Nfd7 f4 c5 Nf3 +e4 Nf6 e5 Nd5 d4 d6 Nf3 dxe5 +e4 d6 d4 f5 +e4 e5 Bc4 Bc5 d4 +e4 c5 Nf3 e6 d4 cxd4 Nxd4 Nc6 Nc3 a6 +e4 e5 Nf3 Nc6 d4 exd4 Nxd4 Nf6 Nxc6 bxc6 e5 +e4 e5 Nf3 d6 d4 exd4 Nxd4 g6 +e4 e5 f4 exf4 Nf3 Ne7 +e4 Nf6 e5 Nd5 d4 d6 c4 +d4 Nf6 Nc3 d5 Bg5 +e4 d5 exd5 Nf6 d4 Nxd5 Nf3 Bg4 +e4 e6 b3 d5 Bb2 +e4 e5 Nf3 Nf6 Nxe5 Nc6 Nxc6 dxc6 +e4 e5 d4 exd4 f4 +e4 c5 Nf3 Nc6 b4 +c4 Nf6 Nc3 c5 g3 +c4 e5 Nc3 Nf6 Nf3 Nc6 g3 +e4 c6 d4 d5 exd5 cxd5 c4 Nf6 Nc3 +e4 e5 Nc3 Nf6 Bc4 Bb4 +Nf3 d5 g3 c5 Bg2 Nc6 d4 +e4 e5 Nf3 Nc6 Nc3 Nf6 a3 +e4 f6 d4 Kf7 +e4 c5 f4 d5 Nf3 dxe4 +d4 d5 c4 Nc6 Nf3 Bg4 +d4 Nf6 c4 e6 Nc3 Bb4 Qb3 +e4 e5 Nf3 Nc6 Bb5 f5 Bxc6 +e4 c6 d4 Nf6 +e4 d5 exd5 Qxd5 Nc3 Qa5 d4 e5 +d4 Nf6 c4 g6 Nc3 Bg7 e4 d6 Nge2 +d4 Nf6 g4 Nxg4 +e4 e6 d4 d5 Nc3 Bb4 e5 c5 a3 +e4 c5 Nf3 Nc6 d4 cxd4 Nxd4 Nf6 Nc3 e5 Nb3 +e4 e5 Nf3 Nf6 d4 d5 +d4 d5 c4 c6 Nf3 Nf6 e3 Bg4 +d4 Nf6 c4 c5 d5 d6 +e4 c6 d4 d5 exd5 cxd5 c4 Nf6 Nc3 Nc6 Nf3 Bg4 +e4 e6 d4 d5 Nc3 Bb4 Bd2 +e4 c5 Nf3 a6 Nc3 +d4 d5 c4 e6 Nc3 c5 cxd5 exd5 +e4 e5 Nf3 d6 d4 Nf6 Nc3 Nbd7 +d4 Nc6 d5 Nb8 +e4 e5 Nf3 Nf6 Nxe5 d6 Nxf7 Kxf7 Bc4+ +e4 e5 f4 Nc6 Nf3 f5 +b3 d5 Ba3 +e4 e6 d4 d5 Nc3 Bb4 e5 c5 a3 Bxcbxc3 +e4 g5 d4 Bg7 +e4 e5 Nf3 Nc6 Bb5 f5 exf5 +f4 e5 fxe5 Nc6 +e4 a6 d4 b5 Nf3 Bb7 Bd3 e6 +c4 e5 Nc3 Nf6 g3 Bb4 +e4 e5 d4 exd4 c3 dxc3 Bc4 cxb2 Bxb2 d5 +e4 c6 Nc3 d5 Qf3 +d4 Nf6 c4 d6 Nc3 Bf5 +e4 e5 Nf3 Nc6 d4 exd4 Nxd4 Nxd4 Qxd4 d6 Bd3 +e4 e5 Nf3 f6 Nxe5 fxe5 Qhg6 QxeQe7 Qxh8 +d4 Nf6 c4 e6 Nc3 Bb4 a3 Bxcbxc3 O-O +e4 c5 d4 cxd4 c3 d5 +e4 e5 Nf3 f5 d4 +e4 b6 d4 Ba6 +e4 e6 d4 d5 c4 dxe4 +e4 e6 d4 d5 Nc3 Nf6 Bg5 Be7 e5 Nfd7 h4 +e4 e5 Nf3 f5 Nxe5 Qe7 +e4 e5 Nf3 Nc6 Bc4 Nf6 Ng5 Nxe4 +e4 Nf6 e5 Nd5 c4 Nb6 a4 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 Nf6 O-O Be7 d3 +e4 c5 Nf3 d6 d4 cxd4 Nxd4 Nf6 Nc3 g6 Be3 Bg7 f3 Nc6 +e4 c5 Nf3 a6 d4 cxd4 Qxd4 +d4 d5 c4 c6 Nc3 dxc4 e4 +e4 b6 d4 Bb7 Nf3 +e4 e5 Nf3 Nc6 d4 exd4 c3 dxc3 Nxc3 Bb4 +d4 Nf6 c4 g6 Nf3 d5 +d4 d5 Nc3 e5 +d4 c5 d5 e5 e4 d6 +b4 d5 Bb2 Bf5 +b4 e5 Bb2 f6 b5 +Nf3 d5 g3 e5 +e4 c5 Nf3 Nc6 d4 cxd4 Nxd4 g6 c4 Bg7 Be3 +d4 d5 c4 c5 dxc5 d4 +e4 e5 Nf3 Nf6 Nxe5 d6 Nf3 Nxe4 d3 +e4 c6 d4 d5 Nc3 dxe4 f3 +d4 d6 Nf3 Bg4 +e4 e5 Nf3 Nf6 Nxe5 Nc6 +d4 Nf6 c4 g6 Nc3 Bg7 e4 d6 Bg5 +d4 Nf6 c4 g6 Nc3 Bg7 e4 d6 h3 +e4 g6 d4 Nf6 +c4 e5 Nc3 Nf6 g3 c6 +e4 e5 Nf3 d6 d4 exd4 c3 +e4 c5 Nf3 Nc6 d4 cxd4 Nxd4 g6 c4 Bg7 +e4 c5 Nf3 Nc6 d4 cxd4 Nxd4 d5 +e4 d5 exd5 Nf6 d4 Nxd5 c4 Nb4 +e4 c6 Nf3 d5 exd5 cxd5 Ne5 +e4 e5 Bc4 Nf6 d4 exd4 Nf3 Nxe4 Qxd4 +d4 d5 c4 e5 dxe5 d4 e3 BbBd2 dxe3 +e4 e5 Nf3 Nc6 Bc4 Bc5 Bxf7+ +e4 d6 d4 Nf6 Nc3 g6 f4 Bg7 Nf3 O-O Bd3 +e4 e5 f4 exf4 Nf3 d5 exd5 Nf6 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 Nf6 O-O b5 Bb3 d6 +e4 c5 f4 e5 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 b5 Bb3 Na5 +d4 d5 c4 dxc4 e4 c5 +e4 c5 Nf3 Nc6 d4 cxd4 Nxd4 Nf6 Nc3 e5 Nf3 +e4 e5 Nf3 Nc6 Bc4 Bc5 b4 Bb6 +d4 d5 e4 dxe4 Nc3 Nf6 Bg5 +e4 c5 Nf3 d6 d4 cxd4 Nxd4 Nf6 Nc3 g6 f4 +d4 d5 c4 dxc4 Nf3 b5 +e4 Nc6 d4 d5 Nc3 dxe4 +e4 d6 d4 Nf6 Nc3 Nbd7 f4 e5 +e4 e5 Nf3 Nc6 Bc4 Bc5 b4 Bxb4 c3 Be7 +e4 e5 Nf3 Nf6 Bc4 Nxe4 Nc3 +d4 d5 Nf3 Nf6 Bg5 Ne4 +e4 Nf6 e5 Nd5 c4 Nb6 c5 Nd5 Bc4 e6 Nc3 +e4 c5 Nf3 d6 d4 cxd4 Nxd4 Nf6 Nc3 a6 g3 +e4 e5 f4 exf4 Nf3 g5 h4 g4 Ne5 h5 +e4 d6 d4 Nf6 Nc3 g6 Bc4 +e4 d5 exd5 Nf6 d4 Bg4 +e4 d5 exd5 Qxd5 Nc3 Qa5 b4 +d4 Nf6 c4 g6 Nc3 d5 cxd5 Nxd5 e4 Nxc3 bxc3 Bg7 Nf3 c5 +f3 e5 Kf2 +e4 e6 d4 d5 Nc3 Bb4 e5 c5 a3 Bxcbxc3 Ne7 Qg4 +e4 d6 d4 Nf6 Nc3 g6 Nf3 Bg7 Be2 +e4 e6 d4 d5 Nd2 c5 exd5 Qxd5 +d4 Nf6 c4 e6 Nf3 BbNbd2 +e4 d5 exd5 Qxd5 Nc3 Qa5 d4 Nf6 Nf3 Bf5 +e4 d6 d4 Nf6 Nc3 g6 Nf3 Bg7 h3 +d4 Nf6 c4 e6 Nf3 b6 Nc3 Bb4 +e4 c5 Nc3 e6 g3 d5 +d4 e5 dxe5 Nc6 Nf3 Nge7 +e4 e5 Nf3 Nc6 Nc3 f5 +e4 e5 f4 exf4 Nf3 g5 Bc4 g4 Ne5 +e4 e5 Nf3 Nf6 Nxe5 d6 Nxf7 Kxf7 d4 +e4 c5 c3 d5 exd5 Qxd5 d4 Nf6 Nf3 Bg4 +d4 f5 e4 fxe4 Nc3 Nf6 Bg5 +c4 c5 Nc3 Nf6 Nf3 +e4 c5 Nc3 Nc6 Nge2 +e4 e6 d4 d5 Nd2 Be7 +e4 c5 Nf3 d6 Bd3 +e4 e6 d4 d5 Nd2 Nf6 e5 Nfd7 Bd3 c5 c3 Nc6 Ne2 cxd4 cxd4 +e4 c5 Nf3 Nc6 d4 cxd4 Nxd4 Nf6 Nc3 e5 Nxc6 +e4 e5 Nf3 Nc6 Bc4 Nf6 Ng5 d5 exd5 Nxd5 d4 +b3 e5 Bb2 Nc6 c4 Nf6 +e4 c5 Nf3 d6 d4 cxd4 Nxd4 Nf6 Nc3 a6 Bc4 e6 Bb3 b5 +e4 d5 exd5 Nf6 d4 Bg4 Nf3 +e4 e6 d4 d5 Nc3 Nf6 Bg5 Bb4 +e4 e6 d4 d5 Nc3 Nf6 Bd3 +e4 c5 d4 cxd4 f4 +d4 d5 e4 dxe4 Nc3 Nf6 +Nf3 d5 g3 g6 +e4 e6 Nc3 d5 f4 +e4 c5 d4 cxd4 c3 dxc3 Nf3 +e4 e5 Nc3 Nf6 Bc4 Bc5 d3 +e4 g6 d4 Bg7 Nc3 c5 Be3 +e4 e5 Nf3 Nc6 c3 Nf6 Bc4 +e4 c5 Ke2 +e4 Nf6 e5 Nd5 c4 Nf4 +e4 e6 d4 f5 +e4 c6 d4 d5 Nc3 dxe4 Nxe4 Nf6 Bd3 +e4 Nf6 e5 Nd5 d4 d6 Nf3 g6 +d4 Nf6 c4 e6 Nc3 Bb4 e3 O-O a3 Bxcbxc3 +e4 c6 Bc4 d5 Bb3 dxe4 Qh5 +e4 c5 Nf3 d6 b4 +e4 c5 Nf3 e6 b4 +e4 d5 exd5 Nf6 d4 Nxd5 Nf3 g6 +d4 d5 e4 dxe4 Be3 +d4 g6 c4 Bg7 Nc3 c5 e3 +e4 e5 d4 exd4 Bd3 +e4 c6 d4 d5 exd5 cxd5 Bd3 Nc6 c3 Nf6 Bf4 +e4 e5 Nf3 Nc6 Bb5 Nf6 d3 d6 Bxc6+ +e4 Nc6 d4 d5 exd5 Qxd5 Nc3 +e4 Nf6 Nc3 d5 e5 Nfd7 e6 +e4 e5 Bc4 Nf6 f4 +d4 Nf6 c4 e6 g3 d5 Bg2 Be7 Nf3 +d4 Nf6 c4 e6 Nf3 d5 Nc3 Bb4 +d4 d5 c4 dxc4 Nf3 c5 +d4 d5 c4 c6 Nf3 Nf6 cxd5 cxd5 +d4 g6 c4 Bg7 Nc3 d6 e4 Nc6 +e4 c5 Nf3 e6 d4 cxd4 Nxd4 Nf6 Nc3 Bb4 e5 +e4 e5 Nf3 Nf6 Nxe5 d6 Nc4 +d4 Nf6 Nf3 e6 Nc3 d5 Bg5 +e4 e6 d4 d5 Nc3 Bb4 e5 c5 Bd2 +e4 Nc6 d4 e5 dxe5 Nxe5 f4 Nc6 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 Nf6 O-O d6 +d4 Nf6 c4 g6 Nc3 Bg7 Nf3 d6 Bg5 +e4 e5 Nf3 d5 exd5 Bd6 +e4 c6 d4 d5 exd5 cxd5 c4 Nf6 Nc3 Nc6 +e4 c5 Nf3 d6 d4 cxd4 Nxd4 Nf6 Nc3 Nc6 Bc4 +e4 Nc6 d4 e5 dxe5 Nxe5 Nf3 +e4 c6 d4 d5 Nc3 dxe4 Nxe4 Nd7 Nf3 Ngf6 Ng3 +e4 e5 f4 exf4 Nf3 Be7 Bc4 Bhg3 fxg3 O-O gxhKh1 +e4 d6 d4 Nf6 Nc3 g6 f4 Bg7 Nf3 O-O +d4 d5 c4 Nc6 Nc3 dxc4 Nf3 +d4 d5 g4 +e4 e5 Nf3 Nc6 Bb5 a6 Bxc6 dxc6 d4 exd4 Qxd4 Qxd4 Nxd4 Bd7 +d4 Nf6 c4 e6 Nf3 d5 Nc3 c5 +d4 Nf6 c4 c5 dxc5 e6 +e4 e5 Nf3 Nc6 Bc4 Nf6 d4 d6 +c4 c5 g3 g6 Bg2 Bg7 Nc3 Nc6 +e4 c6 d4 d5 Nc3 g6 +d4 d5 e4 dxe4 Bc4 +e4 e5 Nf3 Nc6 Bb5 Bc5 b4 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 Nf6 Qe2 +e4 e6 d4 d5 e5 c5 c3 Nc6 Nf3 Qb6 a3 Nh6 +e4 c5 d4 cxd4 c3 dxc3 Nxc3 Nc6 Nf3 g6 +d4 Nf6 Nc3 e5 +e4 c5 Nf3 d6 BbBd7 BxdQxd7 c4 +e4 c5 Nf3 d6 d4 cxd4 Nxd4 Nf6 Nc3 g6 Be3 Bg7 Be2 +e4 e6 d4 d5 e5 c5 Qg4 cxd4 Nf3 +e4 c5 Nf3 e6 d4 cxd4 Nxd4 Nf6 Nc3 Nc6 Nxc6 +e4 e5 d4 exd4 c3 dxc3 Bc4 cxb2 Bxb2 Qe7 +e4 c5 h4 +e4 g6 d4 Bg7 Bd3 +e4 e5 Nf3 Nc6 Bb5 Qe7 +c4 f5 e4 +d4 e5 Nf3 e4 Ne5 +e4 e5 Nf3 Nc6 Nc3 Bb4 Nd5 Nf6 +d4 d5 e4 dxe4 Nc3 c5 +d4 d5 c4 e5 dxe5 d4 Nf3 Nc6 g3 +d4 Nf6 c4 e6 Nf3 BbBd2 Bxd2+ +e4 c5 Nf3 e6 d4 cxd4 Nxd4 Nf6 Nc3 d6 +d4 d6 c4 e5 dxe5 Nc6 +d4 d5 Bf4 c5 dxc5 +e4 c5 Nf3 f5 +e4 c5 b4 cxb4 Bb2 +e4 c5 d4 cxd4 c3 e5 +d4 Nf6 c4 g6 Nc3 Bg7 e4 d6 Be2 O-O Be3 +e4 e6 d4 d5 Nf3 dxe4 Ne5 +e4 e5 Nf3 Nc6 Bc4 Bc5 b4 Bxb4 c3 Ba5 d4 d6 +e4 d6 d4 Nf6 Nf3 +e4 e5 Nf3 Nc6 Bb5 f5 Nc3 fxe4 Nxe4 Nf6 +d4 Nf6 c4 g6 Nc3 d5 Bf4 +e4 g6 d4 Bg7 Nf3 d6 c3 +a4 e5 h4 +e4 e6 d4 d5 Nd2 Nc6 Ngf3 Nf6 +e4 e5 f4 exf4 Nf3 g5 Bc4 g4 Ne5 QhKf1 Nh6 d4 d6 +e4 c5 Nf3 a6 c4 e6 +e4 e5 f4 exf4 Bc4 QhKf1 Bc5 +e4 c6 Nc3 d5 Nf3 Bg4 h3 Bxf3 +e4 d6 d4 Nf6 Nc3 g6 f4 Bg7 Nf3 c5 +d4 Nf6 Nf3 c5 d5 b5 +f4 d5 Nf3 Nf6 e3 c5 +d4 d5 c4 dxc4 e4 f5 +e4 e5 Nc3 Nf6 a3 +d4 d5 c4 c6 cxd5 cxd5 Nc3 Nf6 f3 +e4 e5 Nf3 Nc6 Bb5 Nf6 d3 Bc5 Be3 +g4 d5 Bg2 c6 g5 +d4 Nf6 c4 e6 Nc3 Bb4 e3 b6 +e4 e5 f4 Bc5 Nf3 d6 fxe5 +d4 d5 Nc3 Bg4 +e4 c5 d4 cxd4 c3 dxc3 Nxc3 Nc6 Nf3 d6 Bc4 e6 +e4 e5 Nc3 Nc6 d4 +e4 e5 f4 d5 Nc3 +e4 c5 d4 cxd4 c3 dxc3 Nxc3 e6 Nf3 a6 +d4 d5 c4 e6 Nc3 a6 +d4 d5 Nf3 Nf6 e3 g6 Bd3 Bg7 +d4 d5 c4 e6 Nc3 Nf6 Nf3 c5 Bg5 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 Nf6 O-O b5 Bb3 Bb7 +e4 e5 Nf3 Nc6 d4 exd4 Bc4 Nf6 O-O Bc5 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 Nf6 O-O Be7 Re1 d6 +d4 Nf6 c4 e5 dxe5 Ng4 e4 +e4 Nc6 d4 d5 Nc3 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 Nf6 O-O Be7 Bxc6 +d4 d5 c4 e6 Nc3 Nf6 Bg5 Be7 Bxf6 +e4 e6 d4 d5 Nc3 Nf6 Bg5 Be7 e5 Nfd7 h4 a6 +e4 e5 f4 exf4 Nf3 Be7 Bc4 Nf6 +e4 e5 Nf3 f5 Bc4 Nf6 +e4 c5 Nf3 a6 d3 +d4 d5 c4 c6 Nf3 Nf6 Nc3 g6 +e4 d5 exd5 Qxd5 Nc3 Qa5 d4 Nf6 Nf3 Bg4 h3 +e4 e5 f4 exf4 Nf3 g5 h4 g4 Ng5 +e4 e5 Nf3 Nc6 Bb5 Nf6 O-O Ng4 +e4 c6 d4 d5 Nd2 dxe4 Nxe4 Nd7 +c4 Nf6 Nc3 e6 Nf3 Bb4 +Nf3 d5 g3 c5 Bg2 Nc6 d4 Nf6 O-O +e4 e6 d4 d5 c4 +d4 Nf6 c4 e6 Nf3 BbBd2 c5 +e4 e6 d4 d5 Nc3 Bb4 e5 c5 a3 Bxcbxc3 Ne7 Nf3 +e4 c5 d4 cxd4 c3 dxc3 Nxc3 Nc6 Nf3 d6 Bc4 a6 O-O Nf6 +e4 d5 exd5 Qxd5 Nc3 Qd6 d4 c6 +e4 e5 f4 d5 exd5 c6 +e4 c5 d4 cxd4 c3 d3 c4 +e4 e5 Nf3 Nc6 d4 exd4 Bc4 Nf6 O-O d6 +d4 d5 c4 e6 Nc3 Be7 +a3 e5 Nc3 +d4 Nf6 c4 e6 Nc3 Bb4 e3 O-O Ne2 +e4 Nc6 Nf3 Nf6 e5 Ng4 +d4 d5 e4 dxe4 Nc3 Nf6 f3 exf3 Nxf3 Bg4 +e4 c5 Nf3 d6 d4 Nf6 dxc5 Nxe4 +d4 d5 c4 e5 dxe5 d4 Nf3 c5 +e4 e5 f4 exf4 Nf3 g5 h4 g4 Ne5 d6 +d4 Nf6 c4 e6 Nf3 BbBd2 a5 +e4 e5 Nf3 Nf6 Nxe5 d6 Nf3 Nxe4 Bd3 +e4 e5 Nf3 Nf6 Nxe5 d6 +f4 d5 e4 +e4 e5 Nf3 f5 Nxe5 Nc6 +d4 Nf6 c4 g6 Nc3 d5 Nf3 Bg7 Bf4 +d4 d5 e4 dxe4 Nc3 f5 +e4 d5 exd5 e5 dxe6 Bxe6 +e4 c5 Nf3 d6 d4 cxd4 Nxd4 Nf6 Nc3 a6 Be3 e6 f3 +e4 e5 f4 exf4 Bc4 g5 +e4 g6 d4 Bg7 Nc3 b6 +e4 e5 Nf3 d6 d4 Nd7 Bc4 c6 O-O +e4 d5 exd5 Nf6 d4 Bg4 f3 Bf5 c4 +d4 g6 c4 Bg7 Nc3 c5 d5 Bxcbxc3 f5 +e4 c5 Nf3 a6 Be2 +d4 Nf6 c4 e6 Nf3 d5 Nc3 c5 cxd5 +d4 c5 dxc5 Na6 +e4 e5 Nf3 Nc6 Bc4 Nf6 Ng5 d5 exd5 Nb4 +d4 Nf6 c4 g6 Nc3 d5 f3 +e4 c5 Nf3 b5 +e4 e5 Nf3 Nf6 Nxe5 d6 Nf3 Nxe4 d4 Nf6 +c4 e5 Nc3 Nf6 Nf3 Nc6 e4 +e4 e5 f4 exf4 Bc4 d5 Bxd5 Nf6 +d4 Nf6 c4 e6 g3 d5 Bg2 +e4 c6 Nc3 d5 Nf3 Bg4 h3 Bh5 +Nf3 Nf6 g3 d5 Bg2 c6 O-O Bg4 +d4 Nf6 c4 e6 Nc3 d5 cxd5 exd5 Bg5 c6 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 Nf6 c3 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 Nge7 +e4 e5 f4 exf4 Bc4 QhKf1 Nf6 +e4 c6 Nc3 d5 Nf3 Bg4 +d4 Nf6 Bg5 Ne4 Bf4 g5 +e4 c5 Nc3 Nc6 g3 g6 +e4 e6 d4 d5 e5 c5 Qg4 +e4 e5 Nf3 Nc6 c3 f5 +e4 e5 Nc3 Nc6 Bc4 Bc5 Qg4 Qf6 Nd5 +d4 Nf6 f3 d5 e4 +e4 c5 Nf3 Nc6 d4 cxd4 Nxd4 g6 c4 Bg7 Be3 Nf6 Nc3 Ng4 +e4 d5 exd5 Qxd5 Nc3 Qd6 d4 Nf6 Nf3 a6 +d4 Nf6 c4 g6 Nc3 Bg7 e4 d6 f3 O-O Be3 c5 +d4 Nf6 c4 g6 g3 d5 +d4 Nf6 c4 g6 Nc3 Bg7 e4 d6 Nf3 O-O Bg5 +e4 c5 Nf3 a6 b4 +e4 c5 Nf3 e6 d4 cxd4 Nxd4 Nc6 Nc3 Qc7 Be3 a6 Be2 +e4 Nf6 e5 Nd5 c4 Nb6 b3 +e4 e5 Nf3 Nc6 Bb5 Bc5 c3 f5 +e4 d6 d4 Nf6 Nc3 Nbd7 f4 +e4 e5 Nf3 Nc6 Bc4 Bc5 c3 Nf6 b4 +d4 d5 e4 dxe4 Nc3 Nf6 f3 exf3 Nxf3 e6 +e4 c5 a4 +e4 e6 d4 d5 Nc3 Bb4 e5 c5 a3 Ba5 +e4 e5 f4 exf4 Nf3 g5 h4 g4 Ng5 h6 Nxf7 Kxf7 Bc4+ +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 Nf6 O-O Nxe4 Re1 d5 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 d6 c3 Bd7 +e4 c5 Na3 +e4 c5 Nf3 a6 b3 +e4 e5 Nf3 Nc6 Bb5 b6 +e4 c6 d4 d5 exd5 cxd5 c4 Nf6 Nc3 g6 +e4 c5 Nf3 d6 d4 cxd4 Nxd4 Nf6 Nc3 g6 Be3 Bg7 Be2 Nc6 +d4 Nf6 c4 g5 +e4 c5 d4 cxd4 Nf3 e5 c3 +e4 c6 d4 d5 Nf3 dxe4 Ng5 +d4 Nf6 Nc3 d5 Bg5 Ne4 +e4 c5 Nf3 h6 +e4 e5 Nf3 Nc6 Nc3 Nf6 d4 exd4 Nd5 +c4 e5 Nc3 d6 g3 c6 +e4 e6 d4 d5 e5 Bd7 +b3 Nf6 Bb2 g6 g4 +d4 f5 g3 Nf6 Bg2 g6 +e4 e5 f4 exf4 Nf3 g5 h4 g4 Ne5 +e4 e6 d4 d5 Nc3 Nf6 e5 Nfd7 Qg4 +e4 e5 f4 exf4 Nf3 g5 Bc4 g4 Bxf7+ +d4 Nf6 c4 g6 Nc3 Bg7 e4 d6 Nf3 O-O Be2 e5 O-O Nc6 +e4 e5 Nf3 Nc6 Nxe5 Nxe5 d4 +e4 Nf6 e5 Nd5 d4 d6 c4 Nb6 f4 g6 +d4 Nf6 c4 c5 d5 e6 Nc3 exd5 cxd5 d6 e4 g6 f4 Bg7 Bb5+ +d4 Nf6 c4 g6 Nc3 d5 Bf4 Bg7 e3 O-O +d4 d5 e4 dxe4 Nc3 Nf6 f3 exf3 +e4 e5 Nf3 Nc6 c3 d5 Bb5 +d4 Nf6 c4 e6 g3 d5 +e4 e5 Nf3 d6 d4 Nd7 Bc4 c6 Ng5 +c4 Nf6 Nf3 d5 +e4 e5 f4 Bc5 Nf3 d6 c3 +e4 e6 d4 d5 e5 c5 Nf3 cxd4 Bd3 +e4 e5 Nf3 d6 d4 f5 Nc3 +e4 e6 d4 d5 Nc3 Nf6 Bg5 Be7 Bxf6 Bxf6 e5 Be7 Qg4 +e4 e5 Nf3 Nf6 Nxe5 d6 Nf3 Nxe4 d4 d5 Bd3 Be7 O-O O-O +Nf3 d6 d4 e5 +d4 d5 c4 dxc4 e4 e5 Bxc4 +e4 c6 d4 d5 Nd2 dxe4 Nxe4 Bf5 Ng3 Bg6 h4 +e4 c6 d4 d5 exd5 cxd5 c4 Nf6 Nc3 e6 Nf3 Bb4 +e4 Nf6 e5 Nd5 d4 d6 Nf3 Bg4 Be2 c6 +d4 Nf6 c4 e6 Nf3 d5 g3 Be7 Bg2 O-O O-O dxc4 +Nf3 e5 Nxe5 Nc6 Nxc6 dxc6 +e4 e5 Nf3 Nc6 Bc4 Bc5 b4 Bxb4 c3 Bd6 +e4 e5 f4 d5 d4 +d4 e5 dxe5 Qh4 +e4 e5 f4 exf4 Bc4 c6 +e4 c5 Nf3 e6 d4 cxd4 Nxd4 Nf6 Nc3 d6 g4 +e4 e5 Nf3 Nc6 Bc4 Bc5 O-O Nf6 d3 h6 c3 +e4 c5 Nf3 e6 d4 cxd4 Nxd4 Nc6 Nc3 Qc7 Be3 +e4 c5 Nf3 a6 d4 cxd4 c3 +d4 b5 e4 Bb7 Bxb5 +e4 e5 Nf3 Nc6 Bb5 a5 +d4 Nf6 c4 d6 Nc3 c6 +d4 d5 c4 Nc6 Nc3 e5 +e4 c5 Nf3 d6 d4 cxd4 Nxd4 Nf6 Nc3 Nc6 Bg5 e6 Qd2 Be7 +e4 e5 Nf3 Nf6 d4 exd4 e5 Ne4 Qxd4 +d4 d5 c4 Bf5 Nc3 e6 Qb3 +d4 Nf6 c4 c5 d5 b5 cxb5 a6 bxa6 Bxa6 Nc3 d6 e4 +d4 d5 c4 e6 Nc3 c6 e4 dxe4 Nxe4 BbBd2 +c4 e5 Nc3 Nf6 Nf3 Nc6 a3 +e4 c5 Nf3 d6 d4 cxd4 Nxd4 Nf6 Bc4 +e4 e5 Bc4 Nf6 d4 exd4 c3 +e4 c6 d4 d5 exd5 cxd5 c4 Nf6 c5 +e4 e6 d4 d5 Nc3 Nf6 Bg5 Be7 e5 Nfd7 h4 c5 +d4 Nf6 c4 g6 Nc3 Bg7 e4 d6 Nf3 O-O Be2 Nbd7 O-O e5 d5 +Nf3 Nh6 d4 g6 +e4 e5 Nf3 Nc6 Bc4 Bc5 b4 Bxb4 c3 Ba5 O-O Nf6 d4 exd4 +e4 e5 Nf3 Nc6 Bb5 Bc5 c3 Qe7 +e4 e5 f3 Nf6 Nc3 +e4 Nf6 e5 Nd5 d4 d6 c4 Nb6 c5 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 Nf6 O-O Be7 Nc3 +e4 e5 Nf3 Nc6 Bc4 Bc5 c3 Nf6 d3 a6 +e4 e5 f4 exf4 Qf3 +d4 Nf6 c4 e6 Nc3 Bb4 Qc2 O-O a3 BxcQxc3 b6 +d4 Nf6 Nf3 Ne4 +d4 d5 c4 Nc6 Nf3 e5 +d4 Nf6 c4 e6 Nc3 Bb4 e3 O-O Nf3 +c4 Nf6 Nc3 g6 Nf3 Bg7 e4 +e4 c5 Nf3 Nf6 e5 Nd5 Nc3 Nxc3 +d4 d5 c4 e6 Nc3 c5 cxd5 cxd4 +e4 e5 Nc3 Nc6 f4 exf4 d4 +e4 e5 Nf3 Nc6 Bb5 Nd4 Nxd4 exd4 O-O Ne7 +e4 e5 c3 f5 +c4 Nf6 Nf3 d6 +d4 Nf6 c4 e6 Nc3 Bb4 g3 +d4 d5 c4 Nf6 cxd5 c6 +d4 d5 c4 c6 Nf3 Nf6 Nc3 dxc4 a4 Bf5 e3 +e4 c6 d4 d5 Nc3 dxe4 Nxe4 Nf6 Nxfexf6 Bc4 +Nf3 d5 c4 d4 e3 c5 b4 +e4 d6 d4 Nf6 Nc3 g6 f4 Bg7 Nf3 O-O e5 +e4 e6 f4 d5 Nf3 dxe4 +e4 e5 Nf3 Nc6 Bb5 f5 d4 +e4 e5 f4 d5 Nc3 dxe4 Nxe4 +d4 Nf6 c4 g6 Nc3 Bg7 e4 d6 Nf3 O-O Be2 e5 d5 +c4 e5 g3 Nf6 Bg2 d5 cxd5 Nxd5 Nf3 Nc6 +e4 d5 b3 +e4 e5 f4 exf4 Nf3 g5 Nc3 +d4 d5 c4 c5 cxd5 Nf6 +e4 e6 d4 d5 Nc3 dxe4 Nxe4 Qd5 +e4 e5 Nf3 Nc6 c3 Be7 +d4 Nf6 c4 e6 Nf3 b6 a3 Bb7 Nc3 +e4 e6 d4 d5 Nc3 Bb4 e5 c5 Qg4 +e4 e5 Nf3 Nc6 Bb5 Bb4 +e4 e5 f4 exf4 Nf3 h5 +e4 e5 f4 d5 exd5 Bc5 +e4 e5 Nf3 f5 Nxe5 Qf6 d4 d6 Nc4 +e4 c5 Nf3 e6 d4 cxd4 Nxd4 Nf6 Nc3 Bb4 Bd3 e5 +e4 c5 Nf3 d6 d4 cxd4 Nxd4 Nf6 Nc3 Nc6 Bg5 Bd7 +d4 d5 e4 dxe4 Nc3 Nf6 f3 Bf5 +d4 Nf6 c4 c5 d5 e6 Nc3 exd5 cxd5 d6 e4 g6 f4 Bg7 e5 +e4 c5 Nf3 d6 d4 cxd4 Nxd4 Nf6 Nc3 e5 Bb5+ +e4 e5 f4 exf4 Nc3 +d4 d5 c4 Bf5 Nc3 e6 Nf3 Nc6 +e4 Nc6 d4 e5 dxe5 Nxe5 f4 Ng6 +d4 Nf6 c4 g6 Qc2 +d4 Nf6 c4 c5 d5 e6 Nc3 exd5 cxd5 d6 e4 g6 f4 Bg7 Nf3 O-O +d4 Nf6 c4 g6 Nc3 d5 Qb3 +e4 c5 b3 b6 +e4 e5 Nf3 Nc6 Bc4 Nf6 Ng5 Bc5 Nxf7 BxfKxf2 NxeKe3 +d4 Nf6 c4 e6 Nc3 Bb4 e3 c5 Nf3 O-O +e4 e5 Nf3 f5 Bc4 fxe4 Nxe5 d5 +d4 d5 c4 Bf5 Qb3 +e4 c5 Nf3 a6 c3 Nf6 +e4 c6 c4 e5 +Nf3 Nf6 g3 g6 b4 +e4 e5 Ke2 +e4 e6 d4 d5 Be3 +f4 e5 fxe5 f6 +e4 c6 c4 d5 exd5 cxd5 cxd5 Nf6 +e4 c5 Nc3 Nc6 g3 g6 Bg2 Bg7 d3 d6 Be3 +e4 e5 Nf3 Nc6 Bb5 Nge7 Nc3 g6 +e4 d6 d4 Nf6 Nc3 g6 g3 +e4 e5 Nf3 Nc6 Bb5 Nf6 O-O Nxe4 d4 Nd6 dxe5 +e4 e5 Bc4 Nf6 d3 Nc6 Nc3 +d4 d5 c4 dxc4 e4 c5 d5 b5 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 d6 c3 +e4 c5 Nf3 e6 d4 cxd4 Nxd4 Nf6 Nc3 d6 Be2 +d4 d5 c4 e6 Nc3 Nf6 Bg5 c5 +e4 e5 f4 exf4 Nf3 f5 +d4 Nf6 c4 e6 Nc3 Bb4 e3 c5 Ne2 +e4 c5 Nf3 a6 c4 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 f5 +d4 Nf6 Nf3 g6 g3 Bg7 Bg2 O-O O-O d5 c4 +d4 c5 d5 d6 Nc3 g6 +e4 e5 Nf3 Nc6 Nc3 Nf6 Bb5 Nd4 Nxd4 +d4 d5 c4 c6 Nc3 e5 +d4 Nf6 c4 g6 Nc3 Bg7 e4 d6 f3 O-O Be3 c6 Bd3 a6 +d4 Nf6 c4 g6 Nc3 Bg7 e4 d6 f3 O-O Nge2 +e4 e5 Nf3 Nf6 Nxe5 d6 Nxf7 +b4 e6 Bb2 Nf6 b5 d5 e3 +d4 Nf6 Nf3 e6 Bg5 h6 +e4 e5 f4 exf4 Nf3 d6 d4 Nf6 Bd3 +e4 c5 Nh3 +e4 e5 d3 Nf6 f4 Bc5 +Nf3 f5 e4 +e4 e5 Nf3 Nc6 d4 exd4 Nxd4 Nf6 e5 +d4 d5 c4 dxc4 Nf3 Nf6 e3 Be6 +d4 Nf6 c4 g6 Nc3 Bg7 e4 d6 Nf3 O-O Be3 +e4 e5 f4 exf4 Nf3 g5 Bc4 Bg7 O-O +e4 c5 Nf3 Qa5 +d4 d5 e4 dxe4 Nc3 e5 +e4 e5 Nf3 Nc6 d4 exd4 Bb5 +e4 c5 Nf3 e6 d4 cxd4 Nxd4 Qb6 +c4 Nf6 b4 +e4 c5 c3 d5 exd5 Qxd5 d4 cxd4 cxd4 Nc6 Nf3 Bg4 +d4 Nf6 c4 g6 Nc3 d5 cxd5 Nxd5 e4 Nxc3 bxc3 Bg7 Nf3 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 Nf6 d4 +d4 d5 Nf3 Bf5 c4 e6 Nc3 c6 +e4 g6 d4 Bg7 Nc3 c5 dxc5 Qa5 +e4 e5 f4 exf4 Nf3 Be7 Bc4 Bhg3 +c4 e6 Nc3 Nf6 e4 +c4 c5 b4 +e4 e5 Nf3 f6 Nxe5 Qe7 Nf3 d5 +e4 e5 Nf3 Nc6 Bc4 Bc5 b4 Bxb4 c3 Ba5 d4 exd4 O-O dxc3 +e4 e5 Nf3 Nc6 Bc4 Nf6 d4 exd4 e5 Ng4 +e4 e5 Nf3 Nc6 Nxe5 +d4 Nf6 c4 d6 Nc3 Nbd7 e4 e5 Nf3 +e4 e6 d4 f5 exf5 +e4 e5 Nf3 Nc6 b4 +d4 Nf6 Bg5 Ne4 h4 +e4 e6 d4 d5 Nc3 Nf6 Bg5 Bb4 e5 h6 Bd2 Bxc3 +d4 Nf6 c4 c5 d5 b5 cxb5 a6 e3 +d4 e5 dxe5 Nc6 Nf3 Qe7 Qd5 +e4 Nf6 e5 Nd5 Bc4 Nb6 Bb3 c5 d3 +e4 e5 Nf3 Nc6 Bc4 Bc5 O-O Nf6 d3 h6 c3 d6 +d4 d5 c4 e5 dxe5 d4 Nf3 Nc6 g3 Be6 +e4 e6 d4 d5 Nc3 Nf6 Bg5 Be7 e5 Ne4 +d4 Nc6 c4 e5 d5 Nd4 +e4 c6 b4 +d4 Nf6 c4 g6 Nc3 Bg7 e4 d6 f3 O-O Be3 Nc6 Nge2 a6 +e4 e5 f4 exf4 Nf3 g5 d4 g4 Ne5 Qhg3 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 Nf6 Bxc6 +e4 e5 Nf3 f5 Nxe5 Qf6 d4 d6 Nc4 fxe4 Be2 +e4 Nc6 d4 d5 Nc3 dxe4 d5 Ne5 +e4 e6 d4 d5 Nc3 Bb4 e5 c5 a3 Ba5 b4 cxd4 +d4 d5 c4 dxc4 Nf3 Nf6 e3 g6 +e4 c5 Nf3 d6 d4 cxd4 Nxd4 Nf6 Nc3 a6 Bg5 e6 f4 Nc6 +e4 d5 exd5 Nf6 d4 Bg4 Bbc6 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 Nf6 O-O Be7 Re1 b5 Bb3 O-O a4 +e4 e6 d3 f5 +d4 d5 c4 e6 Nc3 Nf6 Bg5 Nbd7 e3 Bb4 +d4 d5 c4 c6 Nf3 Nf6 Nc3 e6 Bg5 Nbd7 e3 Qa5 +e4 c6 d4 Na6 Nc3 Nc7 +e4 c5 Nf3 e6 d4 cxd4 Nxd4 Nf6 Nc3 Qb6 +e4 c6 d4 d5 e5 Bf5 c3 e6 Be2 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 d6 c3 f5 exf5 Bxf5 O-O +e4 e5 Nf3 d6 d4 Bd7 +e4 e5 f4 exf4 Nf3 g5 Bc4 g4 Ne5 QhKf1 f3 +Nf3 d5 g3 Bg4 Bg2 Nd7 +d4 Nf6 c4 g6 Nf3 Bg7 g3 O-O Bg2 d5 cxd5 Nxd5 O-O +d4 Nf6 c4 g6 Nc3 d5 Nf3 Bg7 Bf4 O-O e3 +d4 d5 e4 dxe4 Nc3 Nf6 f3 e5 +e4 g6 Nc3 Bg7 f4 c5 Nf3 Qa5 +e4 Nc6 d4 e5 dxe5 Nxe5 Nc3 +e4 e5 Nf3 f5 Nxe5 Qf6 Nc4 fxe4 d3 +e4 Nf6 e5 Nd5 d4 d6 Nf3 Bg4 h3 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 b5 Bb3 Na5 Bxf7+ +c4 e6 Nf3 d5 g3 c6 +e4 c5 d4 cxd4 c3 Qa5 +e4 e5 Nf3 d6 d4 Nf6 Bc4 +e4 c5 Nf3 d6 d4 cxd4 Nxd4 Nf6 Nc3 Nc6 g3 +e4 c5 c3 Nf6 e5 Nd5 Nf3 Nc6 Bc4 Nb6 Bb3 +e4 d5 b4 +e4 g6 d4 Bg7 Bd2 +d4 d5 Bf4 c5 e4 +d4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bg5 h6 Bh4 O-O e3 Ne4 +e4 e5 Nf3 Nc6 Bc4 Nf6 d4 exd4 Ng5 +e4 c6 d4 d5 exd5 cxd5 c4 Nf6 Nc3 Nc6 Bg5 e6 +d4 e5 Nf3 e4 Ng1 +d4 d5 c4 e6 Nc3 Nf6 Nf3 Be7 Bf4 O-O e3 c6 +e4 e5 Nf3 Nc6 Bc4 Bc5 b4 Bxb4 c3 Ba5 d4 exd4 O-O d3 +d4 Nf6 c4 g6 Nc3 Bg7 e4 d6 Nf3 O-O Be2 e5 d5 a5 +e4 e5 Nf3 d6 d4 Bg4 dxe5 Nd7 +d4 g6 c4 Bg7 Nc3 d6 e4 f5 +e4 e5 Nf3 Nc6 Bb5 Nf6 O-O Nxe4 d4 Nd6 Ba4 +e4 d6 d4 Nf6 Nc3 g6 Nf3 Bg7 Be2 O-O O-O Nc6 +e4 e5 Bb5 Nf6 d4 +d4 Nf6 c4 e6 Nc3 Bb4 Qd3 +e4 e5 Nf3 Nc6 Bc4 Bc5 b4 Bxb4 c3 Ba5 d4 exd4 O-O d6 Qb3 +e4 e6 d4 d5 Nc3 Nf6 Bg5 Bb4 e5 h6 exf6 +d4 f5 Nc3 d5 e4 +e4 c5 Nf3 a6 g3 +d4 Nf6 c4 e6 Nc3 d5 cxd5 exd5 Bg5 c6 Qc2 +e4 d5 exd5 Nf6 d4 Bg4 f3 Bf5 g4 +e4 e5 Nf3 Nf6 Nxe5 d6 Nf3 Nxe4 c4 +e4 Nf6 e5 Nd5 d4 d6 c4 Nb6 f4 Bf5 +d4 d5 c4 c6 e4 +e4 e6 d4 d5 Nc3 Nf6 Bg5 Bb4 e5 h6 Bh4 +e4 Nf6 Nc3 d5 exd5 c6 +e4 e5 f4 d5 exd5 e4 Bb5+ +d4 Nf6 c4 e6 Nc3 Bb4 Qc2 d5 a3 BxcQxc3 Ne4 Qc2 +e4 c5 Nf3 d6 d4 cxd4 Nxd4 Nf6 Nc3 a6 Rg1 +d4 d5 c4 c6 Nf3 Nf6 Nc3 dxc4 a4 Bf5 +e4 c5 Nf3 d6 d4 cxd4 Nxd4 Nf6 Nc3 a6 Bg5 e6 f4 b5 +e4 e5 f4 f5 exf5 exf4 QhKe7 +e4 e5 Nf3 Nc6 d4 exd4 Bc4 Bc5 Ng5 Nh6 Qh5 +e4 e5 Nf3 Nf6 Nc3 +e4 e5 Nf3 d6 Bc4 +c4 Nf6 e4 +e4 e5 Nf3 Nc6 Nc3 Nf6 d4 Bb4 d5 Nd4 +d4 f5 c4 Nf6 g3 e6 Bg2 Be7 +f4 e5 fxe5 d6 exd6 Nf6 +d4 Nf6 c4 g6 h4 +d4 d5 e4 dxe4 Nc3 e5 dxe5 +e4 e5 Nf3 Nc6 Bb5 Nf6 d4 exd4 O-O +Nf3 Nf6 g3 g6 Bg2 Bg7 O-O O-O d3 d5 +e4 c5 Nf3 e6 d4 cxd4 Nxd4 a6 c4 g6 +e4 e6 d4 d5 Nc3 Bb4 Ne2 dxe4 a3 BxcNxc3 Nc6 +d4 d5 c4 c6 Nf3 Nf6 Nc3 Qb6 +e4 c5 Qg4 +e4 c5 Nf3 d6 d4 cxd4 Nxd4 Nf6 Nc3 g6 g3 +e4 e6 d4 d5 Nc3 Nf6 Bg5 dxe4 Nxe4 Be7 Bxf6 Bxf6 Nf3 O-O +d4 Nf6 Bg5 Ne4 h4 Nxg5 hxg5 e5 +d4 f5 Qd3 +d4 f5 c4 Nf6 g3 g6 +d4 d5 e4 dxe4 Nc3 e5 Nxe4 +d4 c5 d5 Nf6 Nc3 Qa5 +b4 d5 Bb2 Qd6 +d4 d5 c4 Nc6 Nc3 dxc4 Nf3 Nf6 +e4 c5 Nf3 a6 c3 d6 +d4 Nf6 g4 +c4 e6 Nc3 Nf6 Nf3 b6 +g4 d5 Bg2 c6 c4 dxc4 b3 +e4 e5 Nf3 Nc6 Nc3 Nf6 d4 Bb4 Nxe5 +e4 d6 d4 Nf6 Nc3 g6 Be2 Bg7 h4 +d4 f5 e4 fxe4 Nd2 +d4 d5 c4 c6 Nf3 Nf6 Nc3 a6 +e4 e5 f4 exf4 Bc4 Ne7 +d4 Nf6 c4 e6 Nf3 a6 +d4 d5 c4 dxc4 Nf3 Nf6 e3 e6 Bxc4 c5 O-O a6 +Nf3 d5 c4 c6 b3 +d4 Nf6 c4 e6 Nf3 b6 a3 Bb7 Nc3 Be7 +b4 e6 Bb2 Nf6 b5 a6 a4 axb5 axb5 Rxa1 Bxa1 +a4 e5 Ra3 +d4 e5 d5 Bc5 e4 Qh4 +e4 d6 d4 Nf6 Nc3 g6 Nf3 Bg7 Be2 O-O O-O c6 +Nc3 e5 Nf3 Bc5 +e4 e6 d4 d5 Nc3 Bb4 e5 Qd7 +d4 d5 c4 dxc4 e3 e5 Bxc4 exd4 Qb3 Qe7 Nf3 +d4 Nf6 c4 e6 Nf3 d5 Nc3 Be7 Bg5 O-O e3 Nbd7 Bd3 +d4 d5 e4 dxe4 Nc3 Nf6 f3 exf3 Nxf3 Bf5 +d4 Nf6 c4 g6 Nc3 d5 cxd5 Nxd5 Na4 +d4 Nf6 c4 g6 Nc3 d5 Nf3 Bg7 e3 O-O Bd3 +d4 g6 Nf3 Bg7 Nc3 d5 +d4 d5 c4 e6 Nc3 Be7 Nf3 Nf6 Bf4 O-O e3 b6 +e4 e5 Nf3 Nc6 Bb5 Nf6 d3 d6 c4 +d4 e6 c4 e5 +Nf3 d5 g3 g6 Bg2 Bg7 O-O e5 d3 Ne7 +e4 Nf6 e5 Nd5 d4 d6 c4 Nb6 Nf3 Bg4 Be2 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 Nf6 O-O b5 Bb3 Be7 a4 +e4 e6 d4 d5 Nc3 Nf6 Bg5 Be7 e5 Nfd7 h4 O-O +e4 c5 b4 cxb4 a3 d5 exd5 Qxd5 Bb2 +e4 e5 Nf3 Nc6 Bb5 Nf6 O-O Bc5 c3 O-O d4 Bb6 +b3 e5 Bb2 Nc6 f4 +e4 c5 Nf3 d6 d4 cxd4 Nxd4 Nf6 Nc3 Nc6 Bg5 e6 Bb5 +g4 e5 h3 Nc6 +e4 e5 Nf3 Nc6 d4 exd4 Nxd4 Bc5 Be3 Qf6 c3 Nge7 Bb5 +e4 e6 d4 d5 e5 c5 b4 +d4 d5 c4 c6 +e4 e6 Nf3 +d4 d5 c4 e5 dxe5 d4 Nf3 Nc6 g3 Bg4 +h4 d5 Rh3 +e4 e6 d4 d5 exd5 exd5 Nc3 Nf6 Bg5 Nc6 +b4 e5 Bb2 f6 e4 +c4 f5 g4 +e4 d6 d4 Nf6 Nc3 g6 Be2 Bg7 g4 +d4 Nf6 c4 e6 Nf3 BbBd2 Nc6 +e4 e6 d4 d5 Nc3 Nf6 Bg5 dxe4 Nxe4 Be7 Bxf6 gxf6 +d4 Nf6 c4 c5 d5 b5 Nf3 +e4 e5 Nf3 Nc6 Bc4 Bc5 b4 Bb6 a4 +e4 e6 d4 a6 c4 b5 +e4 e5 Nf3 Nc6 d4 exd4 c3 d5 +d4 Nf6 c4 Nc6 d5 Ne5 f4 +f4 d5 g4 +e4 e5 d4 exd4 Qxd4 Nc6 Qe3 Bbc3 Be7 +d4 Nf6 c4 e6 Nc3 Bb4 Qc2 d5 a3 +d4 Nf6 c4 e6 Nf3 BbBd2 Be7 +d4 d5 c4 c6 Nf3 Nf6 Nc3 e6 Bg5 Nbd7 e3 Qa5 Nd2 Bb4 Qc2 +c4 g5 d4 Bg7 +c4 Nf6 Nf3 b6 +e4 e5 f4 exf4 Nf3 g5 h4 g4 Ne5 Nf6 Bc4 d5 exd5 Bd6 +d4 Nf6 c4 e6 Nf3 b6 g3 Bb7 Bg2 Be7 O-O +e4 c5 Nf3 Nc6 d4 cxd4 Nxd4 g6 c4 +e4 e5 Nf3 Nc6 Nc3 Nf6 Bb5 Nd4 +e4 e5 Nf3 Nc6 d4 exd4 Bc4 Nf6 O-O Be7 +d4 Nf6 c4 g6 Nc3 Bg7 e4 d6 Nf3 O-O Be2 e5 O-O +d4 d5 c4 c6 Nf3 Nf6 Nbd2 +e4 c5 Nf3 Nc6 Nc3 e5 Bc4 Be7 d3 Nf6 +d4 c5 Nf3 cxd4 b4 +d4 Nf6 c4 e6 Nf3 d5 Bg5 Bb4+ +d4 Nf6 c4 e6 Nf3 b6 a3 Bb7 Nc3 d5 cxd5 exd5 +d4 Nf6 c4 e6 Nc3 Bb4 a3 Bxcbxc3 c5 e3 +e4 d6 d4 Nf6 Nc3 g6 f4 Bg7 Bc4 +d4 f5 c4 Nf6 g3 g6 Bg2 Bg7 Nf3 +e4 c5 Nf3 e6 d4 cxd4 Nxd4 Nf6 Nc3 d6 Bc4 +d4 Nf6 c4 g6 Nc3 Bg7 e4 d6 Be2 O-O Bg5 h6 +e4 e5 Nc3 Nf6 f4 d5 d3 +d4 d5 c4 b5 +c4 Nf6 Nc3 c5 g3 d5 cxd5 Nxd5 Bg2 Nc7 +e4 e5 c4 d5 +e4 e6 d4 d5 Nc3 Bb4 e5 c5 +d4 Nc6 c4 e5 dxe5 Nxe5 Nc3 Nxc4 +e4 c5 Nf3 Qc7 +e4 e5 Nf3 Nc6 d4 Nxd4 Nxd4 exd4 Bc4 +d4 Nf6 Nf3 b5 +c4 e5 Nc3 Nf6 g3 Bc5 Bg2 c6 +e4 e5 Nf3 Nc6 Bb5 Na5 +e4 e5 Nf3 Nc6 Bb5 +e4 e5 Nf3 d6 +d4 f5 c4 Nf6 g3 e6 Bg2 Be7 Nh3 +e4 e5 Nf3 Nc6 Bb5 Nf6 O-O d6 d4 Bd7 Nc3 Be7 Bg5 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 Nf6 O-O Nxe4 d4 b5 Bb3 d5 dxe5 +e4 e6 d4 d5 Nd2 f5 +e4 d5 exd5 Qxd5 Nc3 Qd8 d4 Nf6 Nf3 c6 +e4 c5 Nf3 Nc6 d4 cxd4 Nxd4 Nf6 Nc3 d6 Bd3 +e4 e5 Nf3 Nc6 Bc4 Nf6 Ng5 d5 exd5 Nd4 c3 b5 Bf1 Nxd5 Ne4 +e4 c6 d4 d5 e5 Bf5 Nc3 e6 g4 Bg6 Nge2 c5 h4 +e4 e5 Nf3 d6 d4 Nf6 dxe5 Nxe4 Qd5 +d4 Nf6 c4 g6 Nc3 d5 Nf3 Bg7 Qb3 dxc4 Qxc4 O-O e4 +Nc3 e5 d4 exd4 Qxd4 Nc6 Qa4 +e4 e5 Nf3 Nc6 Bb5 Bc5 c3 d5 +Nc3 Nf6 g4 +e4 c6 d4 Na6 +d4 Nf6 Nc3 d5 Bg5 Bf5 Bxf6 +e4 e6 d4 d5 Nc3 Nf6 Bg5 Be7 Bxf6 +e4 e5 Nf3 Nc6 d4 exd4 Bc4 Nf6 O-O Bc5 e5 Ng4 +e4 e5 Nf3 Nc6 Bc4 Nf6 Nc3 Nxe4 Bxf7+ +e4 e5 Nc3 Nc6 Bc4 Nf6 d3 Bb4 Ne2 +e4 c5 Nf3 a6 c3 b5 +e4 e5 Nf3 Nc6 Bb5 a6 Bxc6 dxc6 O-O Bg4 h3 h5 +d4 d5 c4 c6 Nf3 Nf6 Nc3 e6 Bg5 dxc4 e4 +e4 e6 d4 d5 Nc3 Bb4 e5 c5 a3 Bxcbxc3 Qa5 +e4 e6 d3 d5 Nd2 Nf6 Ngf3 c5 g3 Nc6 Bg2 Be7 O-O O-O Re1 +d4 Nf6 Nc3 d5 Bg5 Nbd7 Nf3 +d4 Nf6 c4 e6 Nf3 b6 g3 Bb7 Bg2 BbBd2 Be7 +e4 e5 Bc4 Bc5 f4 +e4 e5 Nf3 d6 d4 exd4 Nxd4 d5 exd5 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 Nf6 O-O Be7 Qe2 b5 Bb3 O-O +e4 b6 d4 Bb7 f3 e5 +e4 Nc6 Nc3 g6 +e4 b6 d4 Bb7 Bd3 f5 exf5 Bxg2 Qhg6 +e4 e6 d4 d5 Nc3 Nf6 exd5 exd5 Bg5 +e4 Nc6 d4 f6 +e4 e5 Nc3 Nc6 f4 exf4 Nf3 g5 h4 g4 Ng5 +d4 d5 Bg5 Bg4 +c4 e6 Nf3 d5 g3 Nf6 Bg2 Bd6 +e4 e6 d4 d5 Nd2 c5 exd5 exd5 Ngf3 Nc6 +e4 e5 Nc3 Nc6 f4 exf4 Nf3 g5 d4 +e4 d6 d4 Nf6 Nc3 g6 Nf3 +e4 c5 Nc3 Nc6 g3 g6 Bg2 Bg7 d3 d6 f4 +d4 Nf6 Nf3 g6 Bg5 Bg7 Nbd2 d5 e3 O-O +e4 e5 f4 exf4 h4 +e4 e5 Nf3 Nc6 Bc4 Bc5 b4 Bxb4 c3 Ba5 d4 exd4 O-O Nge7 +d4 Nf6 c4 e6 Nc3 d5 Bg5 Be7 e3 Ne4 +d4 Nf6 c4 e6 Nf3 d5 Nc3 Bb4 Qa4+ +e4 e5 f4 f6 fxe5 Nc6 +e4 g6 d4 Bg7 Nc3 c6 Nf3 d6 +e4 Nc6 d4 d5 exd5 Nb4 +d4 d5 c4 c6 Nf3 Nf6 Nc3 e6 Bg5 Nbd7 e3 Qa5 Nd2 dxc4 +d4 d5 c4 dxc4 Nf3 Nf6 e3 Bg4 +e4 g6 d4 f5 +d4 f5 g3 Nf6 Bg2 e6 Nh3 +e4 e5 Nf3 Nc6 Bc4 Bc5 c3 Nf6 d3 d6 O-O O-O +d4 Nf6 c4 e6 g3 d5 Bg2 dxc4 Nf3 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 Nf6 O-O d5 +Nf3 d5 g3 c5 Bg2 Nc6 d4 e6 O-O +d4 Nf6 Nf3 g6 Bg5 Bg7 Nbd2 c5 +d4 Nf6 Nf3 g6 e3 Bg7 Bd3 d6 +e4 e5 Nf3 Bc5 Nxe5 Nc6 +d4 d5 c4 dxc4 Nf3 Nd7 +d4 d5 c4 c6 Nf3 Nf6 Nc3 dxc4 a4 Bg4 +d4 d5 Nf3 Nf6 Bg5 g6 +e4 e6 b4 +e4 e5 Bc4 f5 d3 +e4 e5 f4 d5 exd5 e4 d3 Nf6 dxe4 Nxe4 Qe2 +d4 Nf6 c4 g6 Nc3 Bg7 e4 d6 Nf3 O-O Be2 e5 Be3 +e4 e5 Nf3 Nc6 Bb5 a6 Bxc6 dxc6 O-O Qd6 +e4 e5 Nf3 Nc6 Bb5 a6 Bxc6 dxc6 Nc3 f6 d3 +e4 c5 Nf3 d6 d4 cxd4 Nxd4 Nf6 Nc3 Nc6 Be2 e5 +c4 e5 Nc3 Nf6 g3 g6 +d4 d5 e4 dxe4 Nc3 Nf6 Be3 +d4 d5 c4 c6 Nf3 Nf6 Nc3 dxc4 a4 +b4 e6 Bb2 Nf6 b5 b6 +e4 c5 Nc3 Nc6 g4 +Nf3 c5 c4 g6 d4 Bg7 e4 QaNc3 d6 +d4 Nf6 c4 e6 Nf3 c5 d5 exd5 cxd5 d6 Nc3 g6 e4 Bg7 h3 +e4 e5 f4 exf4 Nf3 g5 Bc4 g4 d4 gxf3 Qxf3 +d4 d5 c4 dxc4 Nf3 Nf6 e3 e6 Bxc4 c5 +e4 e5 Nc3 Nc6 f4 Bc5 fxe5 d6 +d4 Nf6 c4 e6 Nf3 b6 g3 Bb7 Bg2 Be7 O-O O-O Nc3 d5 +e4 e5 Nf3 Nc6 Bb5 Nf6 d3 Ne7 Nxe5 c6 +e4 g5 d4 e5 +e4 e6 d4 d5 Nc3 Nf6 Bg5 Bb4 e5 +e4 g6 d4 Bg7 Nc3 c6 f4 d5 e5 h5 +e4 g6 d4 Bg7 f4 c5 c3 Qa5 +e4 c5 Nf3 d6 d4 cxd4 Nxd4 Nf6 Nc3 a6 Be3 e6 Qd2 +d4 g6 c4 Bg7 Nc3 c5 d5 Bxcbxc3 Qa5 +d4 Nf6 c4 c5 d5 e6 Nc3 exd5 cxd5 Bd6 +d4 Nf6 c4 e6 Nf3 c5 d5 exd5 cxd5 d6 Nc3 g6 e4 +e4 Nf6 e5 Nd5 d4 d6 Nf3 Bg4 c4 +Nf3 d6 e4 Bg4 +e4 g6 d4 Bg7 Nc3 d5 +e4 e5 Nf3 Nc6 Nc3 Nf6 d4 exd4 Nd5 Nxe4 Qe2 f5 +e4 c5 Nf3 e6 d4 cxd4 Nxd4 a6 Bd3 Bc5 +Nf3 d5 b3 c5 e4 +e4 e5 f4 exf4 Bc4 QhKf1 b5 +e4 e5 Nf3 Nc6 Bc4 Bc5 b4 Bxb4 c3 Bf8 +Nf3 Nf6 c4 c6 b3 d5 Bb2 +e4 c6 d4 d5 e5 Bf5 b4 +d4 Nf6 c4 g6 f3 d5 +e4 e5 Nf3 Qf6 Bc4 Qg6 O-O +d4 f5 c4 Nf6 Nc3 d6 Nf3 Nc6 +e4 e6 d4 d5 Nc3 Bb4 e5 c5 a3 Bxcbxc3 Ne7 +d4 Nf6 c4 e6 Nf3 d5 Bg5 h6 +e4 c6 d4 d5 e5 Bf5 Nc3 Qb6 +e4 e5 Nf3 Nc6 Nc3 Nf6 d4 exd4 Nxd4 Nxe4 +d4 Nf6 c4 e6 Nc3 Bb4 f3 d5 a3 Bxcbxc3 c5 cxd5 +d4 Nf6 c4 e6 Nf3 d5 Nc3 Be7 Bf4 +e4 c5 Nf3 Nc6 d4 cxd4 Nxd4 e5 Nb5 d6 +e4 g6 d4 Bg7 +d4 d5 c4 Bf5 +d4 c5 d5 d6 +d4 Nf6 Nf3 g6 +d4 d5 c4 dxc4 e3 +e4 c5 c3 +d4 d5 Bf4 +e4 c5 Bc4 +e4 d5 exd5 Qxd5 Nc3 Qd8 +e4 e6 Nf3 +d4 d5 Nf3 Nf6 Bf4 +d4 Nf6 Bg5 +e4 e5 Nf3 d6 d4 +e4 c6 d4 d5 Nc3 dxe4 +e4 c6 d4 d5 Nc3 dxe4 +d4 d5 Bf4 +e4 e5 Nf3 Nc6 Bc4 Bc5 O-O Nf6 d3 h6 c3 +e4 c5 Nf3 e6 d4 cxd4 Nxd4 Bc5 +d4 d5 c4 e6 +e4 c6 d4 d5 exd5 cxd5 c4 +d4 d6 c4 +e4 e5 Nf3 Nc6 Bb5 +e4 e6 Nf3 +e4 Nc6 d4 d6 +e4 c6 d4 d5 exd5 cxd5 c4 +e4 c6 d4 +e4 e5 Nf3 d6 +e4 e5 Nf3 Nc6 Bc4 d6 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 Nf6 d3 +d4 d5 c4 Nf6 +e4 e5 Nf3 d5 +e4 e5 Nf3 Bc5 +e4 e5 Nf3 Nc6 d4 +d4 Nf6 c4 e6 Nc3 Bb4 Bg5 +e4 e5 Nf3 d6 Bc4 Be7 c3 +d4 Nf6 g3 +d4 d5 c4 e5 +e4 c5 Nf3 d6 d4 cxd4 c3 +e4 c5 Bc4 +e4 c5 c3 +e4 e6 Nf3 +d4 d5 c4 dxc4 e4 b5 +e4 c5 Bc4 +e4 e5 Nf3 Bc5 +e4 e5 Nf3 Nc6 c3 +e4 Nf6 e5 Nd5 d4 d6 c4 Nb6 exd6 +d4 Nf6 c4 c5 d5 b5 cxb5 a6 e3 +d4 d5 e3 +e4 e5 Nf3 d6 +c4 Nf6 Nc3 d5 +e4 e5 Bc4 Nf6 +d4 f5 Bg5 +d4 d5 f4 +Nf3 Nf6 b3 +e4 Nc6 d4 d5 e5 +d4 e5 dxe5 Nc6 Nf3 Qe7 Qd5 +e4 e5 Qh5 +e4 e5 Nf3 Nc6 d4 +Nf3 d5 g3 +d4 e6 c4 b6 +e4 e5 Bd3 +e4 e6 b3 d5 Bb2 +e4 e6 d4 d5 exd5 +e4 Nf6 e5 Nd5 c4 Nb6 a4 +d4 c5 d5 Nf6 +e4 c6 d4 d5 exd5 cxd5 Nf3 Nc6 +e4 c6 Bc4 +e4 e6 Nf3 +e4 d6 d4 Nd7 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 b5 +e4 c5 Nf3 Nc6 Bb5 +e4 e5 Nf3 f6 +d4 d5 Nf3 Nf6 e3 e6 +e4 c5 Nc3 +d4 d5 c4 e6 +e4 e5 Nf3 Bc5 +d4 d5 c4 e6 +e4 e5 Nf3 d6 d4 +e4 e5 Qh5 +e4 e5 d4 exd4 Qxd4 +e4 e5 Qf3 +e4 c6 d4 d5 Nc3 dxe4 +e4 c5 Nf3 Nc6 d4 cxd4 Nxd4 g6 Nc3 +e4 d6 d4 e5 +d4 d5 c4 e6 +e4 c5 Nc3 +e4 e5 Bc4 +e4 c5 a3 +e4 e5 Bc4 +e4 e5 Nf3 Nc6 Bc4 d6 +d4 d5 Bg5 +e4 e5 Nf3 Nc6 c3 +e4 e6 d4 d5 exd5 +e4 e5 Nf3 d5 +e4 e5 Bc4 Nf6 +d4 Nf6 c4 e6 Nc3 Bb4 +e4 e5 Bc4 Nf6 d4 +d4 d5 c4 dxc4 e3 +d4 d5 e4 +d4 d5 e4 dxe4 Nc3 Nf6 f3 exf3 Qxf3 +e4 e5 Nf3 d6 Bc4 +d4 Nf6 c4 e6 Nf3 d5 Nc3 dxc4 +d4 Nf6 c4 e6 Nf3 d5 Nc3 dxc4 +e4 c6 d4 d5 f3 +e4 e5 Nf3 Nc6 Bc4 Nf6 d3 Bc5 +d4 Nf6 Bg5 +d4 d5 Bf4 +e4 e5 Nf3 d6 +e4 e6 d4 d5 Nc3 Bb4 e5 +d4 d5 c4 Nf6 +e4 e6 Nf3 +e4 e5 d4 +d4 e6 c4 b6 +d4 d5 e3 Nf6 +e4 e5 f4 Qf6 +e4 c5 Nc3 +d4 Nf6 c4 e5 +e4 d5 exd5 Qxd5 Nc3 Qd8 +e4 e5 Nf3 Nc6 Bc4 d6 +e4 e5 a3 +e4 e6 d4 d5 exd5 +d4 Nf6 d5 +d4 d5 e4 +e4 e5 Nf3 d5 +e4 e5 Nf3 d6 Bc4 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 Nf6 O-O Be7 d3 +d4 d5 e3 Nf6 +e4 c5 Bc4 +e4 e5 Nc3 Bc5 Qg4 +e4 e6 d4 d5 e5 c5 c3 Nc6 Nf3 Bd7 +e4 e5 Nc3 Bc5 Qg4 +e4 e5 Bc4 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 b5 +e4 Nc6 d4 e5 +e4 c5 Nf3 e6 b4 +e4 g6 d4 Bg7 +d4 d5 Nf3 Nc6 +e4 c5 b4 +e4 e5 f4 exf4 Nf3 d6 +e4 e5 Nf3 Nc6 Nc3 +e4 c5 d4 cxd4 c3 +d4 d5 c4 c6 cxd5 +e4 e5 d4 exd4 f4 +d4 d5 c4 Nf6 +e4 d6 d4 Nf6 Nc3 Nbd7 f4 e5 +e4 e5 Qh5 +e4 d5 exd5 Qxd5 Nc3 Qd8 +e4 e6 d4 d5 +g4 d5 Bg2 +e4 e5 Bc4 +e4 c5 Nf3 e6 d4 cxd4 Nxd4 a6 +d4 Nf6 c4 c5 +e4 e5 Nf3 d6 Bc4 +e4 c5 Bc4 +e4 e5 f4 exf4 Nf3 Be7 +e4 e6 d4 d5 exd5 +e4 e5 Nf3 Nf6 Nxe5 d6 Nf3 Nxe4 Nc3 +c4 c5 Nc3 +d4 Nf6 c4 Nc6 +e4 e5 Bc4 +e4 e5 f4 exf4 Nf3 Nf6 +e4 e5 Nf3 d6 d4 +e4 e5 Nf3 Nc6 Bc4 Bc5 Nc3 Nf6 +e4 c5 Nf3 e6 d4 cxd4 Nxd4 Nf6 Nc3 d6 +d4 d5 Bf4 +e4 e5 Bc4 Nf6 +e4 e5 Bc4 Nf6 +e4 c5 d4 cxd4 c3 +d4 d5 c4 e6 +e4 e5 Bc4 +e4 Nc6 d4 e5 +e4 e5 f4 exf4 Nf3 h6 +d4 d5 e3 +e4 c5 Nf3 Nc6 Bb5 +d4 c5 d5 d6 +e4 c5 Nf3 e6 d4 cxd4 Nxd4 Nc6 Nc3 Qc7 Be3 +e4 c5 Nc3 +e4 e5 Nf3 Nc6 Bb5 a6 Bxc6 dxc6 O-O Bd6 +d4 e6 c4 BbNc3 +e4 c5 Nf3 d6 d4 cxd4 Nxd4 Nf6 Nc3 g6 Be3 Bg7 f3 O-O +d4 d6 c4 +e4 e5 Nf3 Nc6 Bc4 Bc5 Nc3 Nf6 +d4 d5 Nf3 Nf6 Bf4 +e4 c5 Nf3 e6 d4 cxd4 Nxd4 a6 +e4 e6 Bb5 +e4 e5 Qf3 +e4 e5 Nf3 d6 Bc4 +d4 d5 c4 e6 +g3 d5 Bg2 c6 +d4 Nf6 Nc3 d5 Bg5 +Nf3 Nf6 b3 +d4 d5 c4 e6 +e4 c5 Nf3 Nc6 Bb5 +e4 e5 Bc4 Nf6 +e4 c5 d4 cxd4 c3 +e4 e6 d4 d5 e5 c5 c3 +d4 d5 e3 Nf6 +d4 d5 c4 dxc4 +e4 e5 f4 d5 exd5 e4 d3 +e4 c5 Nc3 e6 g3 +d4 e5 dxe5 d6 +e4 Nc6 d4 +e4 c5 d4 cxd4 Nf3 +e4 c5 Nf3 d6 d4 cxd4 +e4 e5 Nf3 Nc6 Bc4 Bc5 b4 Bxb4 c3 Be7 +e4 d6 d4 e5 +e4 c5 Bc4 +e4 e6 d4 d5 e5 c5 c3 Qb6 Nf3 Bd7 +e4 e5 Bc4 Nf6 +e4 e5 d4 exd4 Qxd4 +e4 e5 f4 Nf6 +e4 Nf6 e5 Nd5 Bc4 Nb6 Bb3 c5 d3 +d4 d5 c4 dxc4 e3 +e4 c5 d4 cxd4 c3 +d4 Nf6 c4 g6 Nc3 d5 cxd5 Nxd5 +e4 e5 Nf3 Nc6 c3 +e4 c5 Nf3 d6 d4 cxd4 Nxd4 Nf6 Nc3 Nc6 +e4 e5 Nf3 Nc6 Nc3 Nf6 +e4 c6 d4 d5 Nc3 dxe4 +e4 e5 Nf3 Nc6 Bb5 +d4 d6 c4 +d4 Nf6 Bg5 e6 e4 +e4 Nc6 Nf3 f5 +e4 e5 Nf3 d6 d4 +d4 Nf6 c4 c5 d5 e6 Nc3 exd5 cxd5 d6 e4 +e4 e5 Nf3 Nc6 Bb5 +e4 e5 Nf3 d6 d4 +e4 e5 c4 +e4 e5 Nf3 d5 +d4 Nf6 Nf3 g6 Bf4 +e4 e6 Nf3 +e4 e5 Nf3 d6 d4 +e4 e5 Bc4 Nf6 +d4 d5 Bf4 +e4 c5 c3 +e4 c6 Bc4 +g3 d5 Bg2 c6 +e4 Nf6 e5 Nd5 d4 +e4 e5 Nf3 Nc6 Bb5 +e4 e5 Nf3 Nc6 Nc3 +e4 e5 Bc4 +e4 e6 d4 d5 Nc3 Nf6 e5 +e4 c6 d4 d5 exd5 cxd5 Nf3 Nc6 +e4 e5 Nf3 Nc6 Nc3 Bb4 +e4 e6 Nf3 +e4 c6 d4 d5 e5 +d4 d5 c4 e6 +e4 c5 Nf3 d6 Bb5+ +c4 d5 cxd5 Qxd5 Nc3 Qa5 +e4 e5 d4 exd4 c3 +e4 d6 d4 Nf6 Nc3 g6 Bg5 +e4 e5 Qf3 +d4 d5 Bf4 +e4 c5 Nc3 e6 +d4 d5 Bf4 c5 +e4 d5 Nf3 +e4 c5 d4 cxd4 c3 +d4 d5 Bf4 +d4 d5 Bf4 +d4 d5 Bf4 +e4 e5 Bc4 +e4 e5 Nf3 Nc6 Bb5 a6 Bxc6 dxc6 Nc3 +e4 e5 Nf3 Nc6 Bc4 h6 +e4 c6 d4 d5 exd5 cxd5 c4 Nf6 Nc3 e6 +f4 e5 fxe5 d6 exd6 Bxd6 Nf3 g5 +d4 d5 e3 +e4 e5 Nf3 Nc6 Bb5 +e4 c5 Nf3 d6 d4 cxd4 +e4 d5 exd5 Nf6 d4 Nxd5 Nf3 g6 +e4 c5 Nf3 Nc6 d4 cxd4 Nxd4 g6 Nxc6 +d4 d5 Bf4 +e4 c5 Nf3 d6 d4 cxd4 Nxd4 g6 +e4 c5 c3 +e4 e5 Nf3 Nc6 Bc4 d6 +e4 e5 Nf3 d6 Bc4 +e4 e5 Nf3 d6 Bc4 +e4 e5 Nf3 d6 d4 +e4 e5 Nf3 Nc6 Bc4 h6 +e4 e6 d4 d5 exd5 +e4 e5 d4 exd4 Qxd4 +e4 e6 d4 d5 exd5 +e4 e5 Nf3 f6 +e4 e5 Nf3 Nc6 Nc3 Nf6 +e4 c6 d4 d5 Nc3 dxe4 +d4 d5 Nc3 e6 +d4 Nf6 c4 c5 d5 b5 cxb5 a6 +e4 e5 f4 d5 exd5 e4 d3 +e4 e5 Nf3 Nc6 d4 +e4 e6 d4 d5 e5 +e4 e5 Nf3 Nc6 Bc4 h6 +e4 e5 Nf3 d6 Bc4 +e4 c6 d4 d5 exd5 +e4 e5 Nf3 Nc6 d4 exd4 Nxd4 +d4 d5 Bg5 +e4 c5 Nc3 Nc6 f4 +e4 c5 Bc4 +e4 c5 Nf3 e6 d4 cxd4 Nxd4 Nc6 +e4 e5 Nf3 Nc6 Bc4 Nf6 Ng5 d5 exd5 Nd4 +d4 e5 d5 +Nf3 d5 g3 +e4 e5 Nf3 d6 Bc4 +e4 e5 Qh5 +e4 e6 d4 d5 e5 c5 +e4 d5 exd5 Qxd5 Nc3 Qd8 +d4 d5 c4 e5 dxe5 d4 Nf3 Nc6 g3 +e4 c5 Nf3 d6 d4 cxd4 +e4 e5 Nf3 d6 Bc4 +d4 d5 Nc3 +e4 e5 Nf3 Nc6 Bc4 h6 +Nf3 d5 g3 c5 +d4 c5 c4 cxd4 e3 +d4 d5 Bf4 +d4 d5 c4 Bf5 +d4 d5 Bf4 +d4 d5 c4 +e4 d6 d4 e5 +e4 e5 Nf3 f6 +d4 e5 e3 +e4 e5 Nf3 Nc6 d4 exd4 +d4 d5 c4 c6 +d4 g6 c4 Bg7 Nc3 d6 +e4 e6 d4 d5 exd5 exd5 c4 +e4 c5 Nc3 +e4 e5 Nc3 Nc6 g3 +d4 d5 c4 Bf5 +e4 e5 Nf3 Nc6 Bc4 Bc5 O-O Nf6 d3 h6 c3 d6 +e4 e5 Nf3 Nc6 Nc3 Nf6 +e4 e5 Qh5 +e4 e5 Nf3 Nc6 Bc4 h6 +e4 e5 Nf3 Nc6 Bc4 h6 +d4 f5 c4 +e4 e5 Nf3 Nc6 d4 exd4 c3 +e4 e5 Qf3 +e4 c5 Nf3 d6 Bb5+ +e4 c5 Nf3 d6 d4 cxd4 +e4 c5 Nf3 d6 d4 cxd4 +e4 c5 Nf3 d6 d4 cxd4 Qxd4 +e4 e5 Nf3 Nc6 Bb5 +e4 c5 Nf3 e6 d4 cxd4 Nxd4 a6 Nc3 +e4 e5 d4 +e4 e5 Nf3 Bc5 +d4 d5 c4 c6 +d4 d5 Bf4 +d4 Nf6 c4 c5 d5 b5 Nd2 +d4 Nf6 c4 c5 d5 b5 Nd2 +e4 d5 exd5 Qxd5 Nc3 Qd8 +e4 e5 Nf3 Nc6 Bb5 Nge7 +e4 c5 c3 +d4 d5 c4 c6 +e4 c6 d4 +e4 e6 Nf3 +e4 e6 Nf3 +d4 d5 Nc3 +d4 d5 c4 dxc4 e3 +e4 c5 Bc4 +e4 e5 Nf3 Nc6 Bb5 +d4 d5 Nf3 Nf6 e3 e6 +e4 d5 exd5 Nf6 c4 e6 +d4 d5 c4 dxc4 +e4 e5 Nf3 Nc6 d4 Nxd4 +e4 e5 Nf3 Nc6 d4 exd4 Nxd4 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 Nf6 d3 +e4 c5 c3 d5 exd5 Qxd5 +Nf3 d5 d3 +e4 c5 d4 cxd4 Nf3 +e4 c5 Nf3 a6 d4 cxd4 c3 +e4 e5 Nf3 Nc6 Bc4 h6 +d4 d5 e3 +e4 Nc6 d4 d5 Nc3 dxe4 +d4 c5 dxc5 +e4 d5 exd5 Qxd5 Nc3 Qd8 +e4 e5 Nf3 Nc6 Bc4 Nf6 Ng5 d5 exd5 b5 +e4 e5 Nf3 Nc6 d4 exd4 Nxd4 +e4 e6 d4 d5 exd5 +e4 e5 f4 d5 exd5 +e4 e5 Nf3 d6 d4 +e4 c6 d4 d5 exd5 +e4 g6 d4 Bg7 +e4 e5 Nf3 Nf6 Nxe5 d6 Nf3 Nxe4 d4 +e4 e5 d4 exd4 c3 +e4 e6 d4 d5 Nc3 Bb4 e5 +d4 d5 c4 e6 +d4 d5 Bf4 +e4 e5 Nf3 d6 d4 +d4 Nf6 Nf3 g6 +e4 e5 d4 +e4 e6 Nf3 d5 Nc3 +e4 e5 Bc4 +e4 e6 d4 d5 Nc3 dxe4 +e4 e5 Nf3 d6 Bc4 +e4 e5 Nf3 d6 Bc4 +d4 d5 Bf4 +d4 Nf6 c4 e5 +e4 e5 Nf3 d6 d4 +e4 Nf6 e5 Ne4 +e4 e5 Nf3 Nc6 Bb5 a6 Bxc6 bxc6 +e4 c5 c3 +e4 c6 Bc4 +e4 d5 Nf3 +d4 c6 c4 d6 +d4 Nf6 c4 e6 Nc3 d5 cxd5 +e4 e5 Nf3 Nc6 Bb5 Nd4 +e4 e5 Nf3 d6 +e4 e5 Nf3 Nc6 Bc4 h6 +e4 e5 Nf3 d6 +e4 e6 Nf3 +e4 e5 Nf3 d6 Bc4 +e4 e5 Nf3 Nc6 Bc4 Nf6 Ng5 Nxe4 +e4 e6 Nf3 +d4 d5 Nc3 +e4 e6 d4 d5 e5 c5 c3 +d4 d5 Nc3 +e4 Nf6 e5 Nd5 d4 d6 c4 Nb6 exd6 +e4 c5 Nf3 d6 d4 cxd4 Nxd4 Nf6 Nc3 g6 f4 +d4 d5 c4 c6 cxd5 +d4 d6 c4 +e4 e5 Nf3 Nc6 Bc4 Nf6 d4 exd4 +d4 Nf6 c4 e6 Nc3 Bb4 a3 Bxcbxc3 +d4 d5 e3 +d4 d5 c4 c6 Nf3 Nf6 e3 Bg4 +e4 c5 Nf3 e6 b3 +e4 e5 c4 +d4 d5 c4 e5 +e4 c5 Nf3 Nc6 d4 cxd4 Nxd4 g6 +e4 e5 Bc4 Nf6 +e4 e5 Nf3 Nc6 Bc4 Bc5 d3 +d4 d5 c4 Nf6 +e4 e6 d4 a6 +d4 Nf6 Nf3 g6 Bf4 +d4 d5 Nf3 Nf6 e3 +e4 e5 Nf3 Nc6 Bb5 a6 Ba4 Nf6 d3 +e4 e5 Nf3 Nc6 Nc3 Nf6 d4 +d4 Nf6 c4 Nc6 +d4 d5 c4 e6 +e4 c5 c3 d5 exd5 Qxd5 +e4 c5 Nf3 d6 d4 cxd4 +e4 c5 Nf3 Nc6 Bb5 +e4 e5 Bc4 Bc5 +e4 e5 Nf3 Nc6 Bb5 +e4 c6 d4 d5 exd5 +d4 d5 e3 +d4 e6 c4 BbNc3 +e4 e5 Nf3 Nc6 Bc4 Nf6 d4 exd4 O-O +d4 d5 Bg5 +e4 e5 Nf3 Nc6 Bb5 Nge7 +e4 e5 Qf3 +c4 c5 Nc3 Nc6 +e4 e6 d4 d5 e5 +e4 e5 Bc4 +e4 e5 Nf3 Nf6 Nc3 +e4 e6 d4 d5 e5 +d4 Nf6 c4 e5 dxe5 Ng4 Bf4 +e4 e5 Nf3 Nc6 Bb5 +d4 Nf6 c4 e6 Nf3 BbBd2 Bxd2+ +e4 e5 f4 exf4 Nf3 g5 +e4 e5 d4 +e4 e5 Bc4 +b3 e5 Bb2 Nc6 e3 +e4 e5 Bc4 +e4 g6 d4 Bg7 +e4 c5 d4 cxd4 c3 +e4 e5 Nf3 Nc6 Bc4 Nf6 Nc3 +e4 e5 Nf3 Nc6 Nc3 Nf6 +d4 Nf6 d5 +e4 e5 Nf3 d6 Bc4 Be7 +e4 e5 Nf3 Nc6 d4 exd4 Nxd4 +e4 c5 Nf3 d6 b4 +e4 e5 c4 +d4 d5 e3 Nf6 Bd3 +e4 e5 Bc4 Nf6 +e4 c5 Nf3 d6 d4 cxd4 +e4 e5 Nf3 Nc6 Bb5 +d4 Nf6 c4 c5 d5 b5 +e4 c5 Nf3 d6 d4 cxd4 +e4 c5 Bc4 +d4 d5 c4 c6 +d4 Nf6 c4 e5 dxe5 Ng4 Nf3 +d4 Nf6 c4 e5 dxe5 Ng4 +e4 c5 Nf3 d6 d4 cxd4 Nxd4 Nf6 Nc3 a6 Bg5 e6 +e4 e5 Nf3 Nf6 Nxe5 Nc6 Nxc6 dxc6 +d4 d5 e4 dxe4 Nc3 Nf6 Bg5 +e4 e5 Nf3 Nc6 Bb5 Nge7 +d4 d5 e3 +e4 e5 d4 d5 +e4 e5 Nf3 Nc6 Bc4 h6 +e4 e5 Nf3 Nc6 Nc3 Nf6 +e4 c5 Nf3 Nc6 d4 cxd4 Nxd4 g6 Nc3 +e4 e5 Bc4 Nf6 +d4 d5 Nc3 e6 +d4 e6 c4 b6 +d4 d5 c4 e6 Nc3 Nf6 Bf4 +e4 c6 d4 d5 e5 +e4 e5 Nf3 Nf6 Nxe5 Nxe4 +d4 d5 e3 Nf6 +e4 e5 Bd3 +d4 d5 c4 e6 +d4 Nf6 Bg5 Ne4 Bh4 +e4 c5 Bc4 +e4 d5 exd5 Nf6 d4 Nxd5 Nf3 Bg4 +e4 e5 Nf3 Nc6 Bc4 Bc5 d4 +e4 e5 d4 +e4 e5 Nf3 Nc6 Bb5 a6 Bxc6 +e4 e5 f4 d5 exd5 +e4 e5 d4 exd4 Qxd4 +d4 d5 c4 e6 +e4 e5 Nf3 Nc6 d4 exd4 Nxd4 +e4 d5 exd5 Nf6 c4 e6 +d4 d5 e3 +d4 d5 Nc3 +e4 e5 d4 exd4 Nf3 +e4 c5 c3 Nf6 e5 Nd5 d4 cxd4 +e4 d6 d4 Nf6 Nc3 g6 +d4 d5 c4 e5 +e4 e5 Nf3 Nc6 Bb5 Nd4 +d4 d5 c4 Nf6 +e4 g6 d4 Bg7 +e4 e5 d4 exd4 Bc4 +d4 d5 Bf4 +e4 e5 Nf3 d6 Bc4 +e4 c6 d4 d5 e5 Bf5 g4 +d4 d5 c4 dxc4 Nf3 b5 +d4 d5 e3 +d4 d5 c4 e6 +e4 c5 Nf3 d6 d4 cxd4 +e4 c5 Nc3 +e4 c6 d4 d5 Nc3 dxe4 +e4 e6 Nf3 +Nf3 d5 b3 +e4 e5 Nf3 Nc6 Bb5 +e4 e5 Bc4 +d4 Nf6 c4 c5 +d4 d5 c4 e5 +e4 e5 Nf3 Nc6 d4 exd4 Nxd4 +e4 c5 Nc3 e6 +d4 d5 c4 e6 +e4 e6 f4 +e4 g6 d4 Bg7 Nc3 b6 +e4 e5 d4 exd4 Qxd4 +e4 c5 Nf3 d6 d4 cxd4 Qxd4 +e4 e5 d4 exd4 Qxd4 +e4 e5 Nf3 Nc6 Bb5 +Nf3 d5 c4 +e4 e5 Nf3 Nc6 Bc4 Nf6 d3 Bc5 +e4 e5 Bc4 +e4 e5 Nf3 Nc6 c3 +d4 d6 c4 +e4 e6 d4 d5 Nc3 dxe4 +d4 Nf6 Nf3 g6 g3 +e4 e5 d4 exd4 c3 +d4 d5 Qd3 +e4 e5 d4 exd4 Qxd4 +e4 e5 Nf3 Nc6 Bb5 +e4 e5 Nf3 Nf6 Nxe5 +e4 e5 Bc4 +d4 d5 Nc3 +e4 e5 Nf3 d6 +g4 e5 Bg2 d5 c4 +e4 e5 Nf3 Nc6 Bc4 Bc5 Nc3 Nf6 diff --git a/src/test/scala/OpeningTrieTest.scala b/src/test/scala/OpeningTrieTest.scala index 49e2cad..4980964 100644 --- a/src/test/scala/OpeningTrieTest.scala +++ b/src/test/scala/OpeningTrieTest.scala @@ -12,7 +12,7 @@ class OpeningTrieTest extends Specification: "d4 d5" -> 1, "d4 Sf6" -> 2) val bitVectorLength = 3 - val openingTrie = OpeningTrie(openingToCode.asJava, bitVectorLength) + val openingTrie = OpeningTrie(openingToCode.asJava) val pgnMoves = "d4 Sf6 c4".split(" ") val longestCommonOpening = openingTrie.findLongestCommonOpening(pgnMoves) val expectedLongestCommonOpening = "d4 Sf6" From 529e2effcd090fef4eed1ae5ba00a20c24cce35d Mon Sep 17 00:00:00 2001 From: ErdoganSeref Date: Wed, 31 Jul 2024 19:40:02 +0200 Subject: [PATCH 5/9] Avoid unnecessary type conversion In contrast to the corresponding Rust implementation there is no need to convert the integer to a bit vector because the data structure responsible for writing bits to the buffer already supports integers. --- src/main/java/game/OpeningTrie.java | 40 +++++++++++++---------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/src/main/java/game/OpeningTrie.java b/src/main/java/game/OpeningTrie.java index 31e716a..b876af7 100644 --- a/src/main/java/game/OpeningTrie.java +++ b/src/main/java/game/OpeningTrie.java @@ -11,7 +11,7 @@ public class OpeningTrie { private final int bitVectorLength; private final int maxOpeningPlies; - private final Trie openingTrie; + private final Trie openingTrie; public OpeningTrie(Map openingToCode) { this.maxOpeningPlies = getMaxOpeningPlies(openingToCode); @@ -24,9 +24,17 @@ public static OpeningTrie mostCommonOpenings() { return new OpeningTrie(mostCommonOpeningToCode); } - public BitSet get(String opening) { + public int get(String opening) { return openingTrie.get(opening); } + + public Set keySet() { + return openingTrie.keySet(); + } + + public int getBitVectorLength() { + return bitVectorLength; + } public Optional findLongestCommonOpening(String pgnMoves[]) { String openingMoves[] = Arrays.copyOf(pgnMoves, maxOpeningPlies); @@ -73,34 +81,22 @@ private int getMaxOpeningPlies(Map openingToCode) { private int getLowestSufficientBitVectorLength(Integer integers[]) { int max = Arrays.stream(integers).max(Integer::compare).orElse(0); - return (31 - Integer.numberOfLeadingZeros(max)) + 1; + return bitWidth(max); } - private Trie buildOpeningTrie(Map openingToCode) { - Trie openingTrie = new PatriciaTrie<>(); + private Trie buildOpeningTrie(Map openingToCode) { + Trie openingTrie = new PatriciaTrie<>(); for (String opening : openingToCode.keySet()) { - try { - int code = openingToCode.get(opening); - BitSet bitVector = convertIntToBitVector(code); - openingTrie.put(opening, bitVector); - } catch (IllegalArgumentException e) { + int code = openingToCode.get(opening); + if (bitWidth(code) <= bitVectorLength) { + openingTrie.put(opening, code); } } return openingTrie; } - private BitSet convertIntToBitVector(int i) throws IllegalArgumentException { - if (i > (1 << bitVectorLength) - 1) { - String errorMessage = String.format("The integer %d is too large to fit into %d bits", i, bitVectorLength); - throw new IllegalArgumentException(errorMessage); - } - BitSet bitVector = new BitSet(); - int index = 0; - for (int j = bitVectorLength - 1; j >= 0; j--) { - boolean jThBit = ((i >> j) & 1) == 1; - bitVector.set(index, jThBit); - } - return bitVector; + private int bitWidth(int i) { + return (31 - Integer.numberOfLeadingZeros(i)) + 1; } private static Map getMostCommonOpeningToCode() { From ec9babe7317603fcbe81f41a4bb605cee4ce3a57 Mon Sep 17 00:00:00 2001 From: ErdoganSeref Date: Wed, 31 Jul 2024 20:03:23 +0200 Subject: [PATCH 6/9] Refactor move parsing and move format conversion out of class responsible for encoding --- src/main/java/game/CharToRoleConverter.java | 14 +++ src/main/java/game/Encoder.java | 101 +------------------- src/main/java/game/Move.java | 53 ++++++++++ src/main/java/game/SAN.java | 4 + src/main/java/game/SANParser.java | 41 ++++++++ 5 files changed, 116 insertions(+), 97 deletions(-) create mode 100644 src/main/java/game/CharToRoleConverter.java create mode 100644 src/main/java/game/SAN.java create mode 100644 src/main/java/game/SANParser.java diff --git a/src/main/java/game/CharToRoleConverter.java b/src/main/java/game/CharToRoleConverter.java new file mode 100644 index 0000000..971a225 --- /dev/null +++ b/src/main/java/game/CharToRoleConverter.java @@ -0,0 +1,14 @@ +package org.lichess.compression.game; + +public class CharToRoleConverter { + public static Role convert(char c) { + switch (c) { + case 'N': return Role.KNIGHT; + case 'B': return Role.BISHOP; + case 'R': return Role.ROOK; + case 'Q': return Role.QUEEN; + case 'K': return Role.KING; + default: throw new IllegalArgumentException(); + } + } +} diff --git a/src/main/java/game/Encoder.java b/src/main/java/game/Encoder.java index 398f8fe..c71f011 100644 --- a/src/main/java/game/Encoder.java +++ b/src/main/java/game/Encoder.java @@ -21,20 +21,6 @@ protected MoveList initialValue() { } }; - private static Pattern SAN_PATTERN = Pattern.compile( - "([NBKRQ])?([a-h])?([1-8])?x?([a-h][1-8])(?:=([NBRQK]))?[\\+#]?"); - - private static Role charToRole(char c) { - switch (c) { - case 'N': return Role.KNIGHT; - case 'B': return Role.BISHOP; - case 'R': return Role.ROOK; - case 'Q': return Role.QUEEN; - case 'K': return Role.KING; - default: throw new IllegalArgumentException(); - } - } - public byte[] encode(String pgnMoves[]) { BitWriter writer = new BitWriter(); @@ -43,34 +29,8 @@ public byte[] encode(String pgnMoves[]) { for (String pgnMove: pgnMoves) { // Parse SAN. - Role role = null, promotion = null; - long from = Bitboard.ALL; - int to; - - if (pgnMove.startsWith("O-O-O")) { - role = Role.KING; - from = board.kings; - to = Bitboard.lsb(board.rooks & Bitboard.RANKS[board.turn ? 0 : 7]); - } else if (pgnMove.startsWith("O-O")) { - role = Role.KING; - from = board.kings; - to = Bitboard.msb(board.rooks & Bitboard.RANKS[board.turn ? 0 : 7]); - } else { - Matcher matcher = SAN_PATTERN.matcher(pgnMove); - if (!matcher.matches()) return null; - - String roleStr = matcher.group(1); - role = roleStr == null ? Role.PAWN : charToRole(roleStr.charAt(0)); - - if (matcher.group(2) != null) from &= Bitboard.FILES[matcher.group(2).charAt(0) - 'a']; - if (matcher.group(3) != null) from &= Bitboard.RANKS[matcher.group(3).charAt(0) - '1']; - - to = Square.square(matcher.group(4).charAt(0) - 'a', matcher.group(4).charAt(1) - '1'); - - if (matcher.group(5) != null) { - promotion = charToRole(matcher.group(5).charAt(0)); - } - } + SAN sanMove = SANParser.parse(pgnMove, board); + if (sanMove == null) return null; // Find index in legal moves. board.legalMoves(legals); @@ -81,7 +41,7 @@ public byte[] encode(String pgnMoves[]) { for (int i = 0; i < size; i++) { Move legal = legals.get(i); - if (legal.role == role && legal.to == to && legal.promotion == promotion && Bitboard.contains(from, legal.from)) { + if (legal.role == sanMove.role() && legal.to == sanMove.to() && legal.promotion == sanMove.promotion() && Bitboard.contains(sanMove.from(), legal.from)) { if (!foundMatch) { // Encode and play. Huffman.write(i, writer); @@ -143,7 +103,7 @@ public DecodeResult decode(byte input[], int plies) { if (i < plies) { legals.sort(); Move move = legals.get(Huffman.read(reader)); - output[i] = san(move, legals); + output[i] = move.san(legals); board.play(move); if (move.isZeroing()) lastZeroingPly = i; @@ -162,59 +122,6 @@ public DecodeResult decode(byte input[], int plies) { lastUci); } - private static String san(Move move, MoveList legals) { - switch (move.type) { - case Move.NORMAL: - case Move.EN_PASSANT: - StringBuilder builder = new StringBuilder(6); - builder.append(move.role.symbol); - - // From. - if (move.role != Role.PAWN) { - boolean file = false, rank = false; - long others = 0; - - for (int i = 0; i < legals.size(); i++) { - Move other = legals.get(i); - if (other.role == move.role && other.to == move.to && other.from != move.from) { - others |= 1L << other.from; - } - } - - if (others != 0) { - if ((others & Bitboard.RANKS[Square.rank(move.from)]) != 0) file = true; - if ((others & Bitboard.FILES[Square.file(move.from)]) != 0) rank = true; - else file = true; - } - - if (file) builder.append((char) (Square.file(move.from) + 'a')); - if (rank) builder.append((char) (Square.rank(move.from) + '1')); - } else if (move.capture) { - builder.append((char) (Square.file(move.from) + 'a')); - } - - // Capture. - if (move.capture) builder.append('x'); - - // To. - builder.append((char) (Square.file(move.to) + 'a')); - builder.append((char) (Square.rank(move.to) + '1')); - - // Promotion. - if (move.promotion != null) { - builder.append('='); - builder.append(move.promotion.symbol); - } - - return builder.toString(); - - case Move.CASTLING: - return move.from < move.to ? "O-O" : "O-O-O"; - } - - return "--"; - } - private static void setHash(byte buffer[], int ply, int hash) { // The hash for the starting position (ply = -1) goes last. The most // recent position goes first. diff --git a/src/main/java/game/Move.java b/src/main/java/game/Move.java index 7a867bb..c963d8c 100644 --- a/src/main/java/game/Move.java +++ b/src/main/java/game/Move.java @@ -50,6 +50,59 @@ void set(Board board, int type, Role role, int from, boolean capture, int to, Ro public int compareTo(Move other) { return other.score - this.score; } + + public String san(MoveList legals) { + switch (this.type) { + case Move.NORMAL: + case Move.EN_PASSANT: + StringBuilder builder = new StringBuilder(6); + builder.append(this.role.symbol); + + // From. + if (role != Role.PAWN) { + boolean file = false, rank = false; + long others = 0; + + for (int i = 0; i < legals.size(); i++) { + Move other = legals.get(i); + if (other.role == this.role && other.to == this.to && other.from != this.from) { + others |= 1L << other.from; + } + } + + if (others != 0) { + if ((others & Bitboard.RANKS[Square.rank(this.from)]) != 0) file = true; + if ((others & Bitboard.FILES[Square.file(this.from)]) != 0) rank = true; + else file = true; + } + + if (file) builder.append((char) (Square.file(this.from) + 'a')); + if (rank) builder.append((char) (Square.rank(this.from) + '1')); + } else if (this.capture) { + builder.append((char) (Square.file(this.from) + 'a')); + } + + // Capture. + if (this.capture) builder.append('x'); + + // To. + builder.append((char) (Square.file(this.to) + 'a')); + builder.append((char) (Square.rank(this.to) + '1')); + + // Promotion. + if (this.promotion != null) { + builder.append('='); + builder.append(this.promotion.symbol); + } + + return builder.toString(); + + case Move.CASTLING: + return this.from < this.to ? "O-O" : "O-O-O"; + } + + return "--"; + } public String uci() { int to = this.to; diff --git a/src/main/java/game/SAN.java b/src/main/java/game/SAN.java new file mode 100644 index 0000000..98cf9ff --- /dev/null +++ b/src/main/java/game/SAN.java @@ -0,0 +1,4 @@ +package org.lichess.compression.game; + +public record SAN(Role role, long from, int to, Role promotion) { +} diff --git a/src/main/java/game/SANParser.java b/src/main/java/game/SANParser.java new file mode 100644 index 0000000..d518ab8 --- /dev/null +++ b/src/main/java/game/SANParser.java @@ -0,0 +1,41 @@ +package org.lichess.compression.game; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class SANParser { + private static final Pattern SAN_PATTERN = Pattern.compile( + "([NBKRQ])?([a-h])?([1-8])?x?([a-h][1-8])(?:=([NBRQK]))?[\\+#]?"); + + public static SAN parse(String pgnMove, Board board) { + Role role = null, promotion = null; + long from = Bitboard.ALL; + int to; + + if (pgnMove.startsWith("O-O-O")) { + role = Role.KING; + from = board.kings; + to = Bitboard.lsb(board.rooks & Bitboard.RANKS[board.turn ? 0 : 7]); + } else if (pgnMove.startsWith("O-O")) { + role = Role.KING; + from = board.kings; + to = Bitboard.msb(board.rooks & Bitboard.RANKS[board.turn ? 0 : 7]); + } else { + Matcher matcher = SAN_PATTERN.matcher(pgnMove); + if (!matcher.matches()) return null; + + String roleStr = matcher.group(1); + role = roleStr == null ? Role.PAWN : CharToRoleConverter.convert(roleStr.charAt(0)); + + if (matcher.group(2) != null) from &= Bitboard.FILES[matcher.group(2).charAt(0) - 'a']; + if (matcher.group(3) != null) from &= Bitboard.RANKS[matcher.group(3).charAt(0) - '1']; + + to = Square.square(matcher.group(4).charAt(0) - 'a', matcher.group(4).charAt(1) - '1'); + + if (matcher.group(5) != null) { + promotion = CharToRoleConverter.convert(matcher.group(5).charAt(0)); + } + } + return new SAN(role, from, to, promotion); + } +} From bd12d2dc6d7dbecf9a36e4becea043f35c9839b8 Mon Sep 17 00:00:00 2001 From: ErdoganSeref Date: Fri, 2 Aug 2024 19:48:24 +0200 Subject: [PATCH 7/9] Fix longest common prefix implementation Use simpler approach to guarantee correctness first --- src/main/java/game/OpeningTrie.java | 50 ++++++++++++++--------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/src/main/java/game/OpeningTrie.java b/src/main/java/game/OpeningTrie.java index b876af7..f5c39e0 100644 --- a/src/main/java/game/OpeningTrie.java +++ b/src/main/java/game/OpeningTrie.java @@ -37,37 +37,35 @@ public int getBitVectorLength() { } public Optional findLongestCommonOpening(String pgnMoves[]) { - String openingMoves[] = Arrays.copyOf(pgnMoves, maxOpeningPlies); - Optional currentLongestCommonOpening = Optional.empty(); - long currentLongestCommonOpeningLength = 0; - int fromIndex = 0; - int toIndex = openingMoves.length; - while (toIndex >= fromIndex) { - int middleIndex = Math.floorDiv(fromIndex + toIndex, 2); - StringBuilder openingBuilder = new StringBuilder(); - for (int i = 0; i <= middleIndex; i++) { - openingBuilder.append(openingMoves[i]); - openingBuilder.append(' '); - } + int argMax = -1; + StringBuilder openingBuilder = new StringBuilder(); + for (int i = 0; i < maxOpeningPlies; i++) { + openingBuilder.append(pgnMoves[i]); String opening = openingBuilder.toString(); - Set commonOpenings = openingTrie.prefixMap(opening).keySet(); - if (commonOpenings.isEmpty()) { - toIndex = middleIndex - 1; + boolean foundLongerCommonOpening = !openingTrie.prefixMap(opening).isEmpty(); + if (foundLongerCommonOpening) { + argMax = i; } else { - String longestCommonOpening = commonOpenings - .stream() - .max(Comparator.comparingLong(o -> o.chars().filter(c -> c == ' ').count())) - .orElseThrow(); - long longestCommonOpeningLength = longestCommonOpening.chars().filter(c -> c == ' ').count(); - if (longestCommonOpeningLength > currentLongestCommonOpeningLength) { - currentLongestCommonOpening = Optional.of(longestCommonOpening); - currentLongestCommonOpeningLength = longestCommonOpeningLength; - } - fromIndex = middleIndex + 1; + break; } + openingBuilder.append(' '); + } + if (argMax == -1) { + return Optional.empty(); + } + StringBuilder longestCommonOpeningBuilder = new StringBuilder(); + for (int i = 0; i <= argMax; i++) { + longestCommonOpeningBuilder.append(pgnMoves[i]); + if (i < argMax) { + longestCommonOpeningBuilder.append(' '); + } + } + String longestCommonOpening = longestCommonOpeningBuilder.toString(); + if (openingTrie.containsKey(longestCommonOpening)) { + return Optional.of(longestCommonOpening); } - return currentLongestCommonOpening; + return Optional.empty(); } private int getMaxOpeningPlies(Map openingToCode) { From 5966ef5d70d339deaf6bab83311904f307119b94 Mon Sep 17 00:00:00 2001 From: ErdoganSeref Date: Tue, 6 Aug 2024 17:55:06 +0200 Subject: [PATCH 8/9] Compress opening phase of a game separately Remove test case related to old encoding format --- src/main/java/game/Encoder.java | 100 +++++++++++++++++----- src/main/java/game/OpeningTrie.java | 11 ++- src/test/scala/HuffmanPgnTest.scala | 127 +--------------------------- 3 files changed, 86 insertions(+), 152 deletions(-) diff --git a/src/main/java/game/Encoder.java b/src/main/java/game/Encoder.java index c71f011..6463b23 100644 --- a/src/main/java/game/Encoder.java +++ b/src/main/java/game/Encoder.java @@ -1,10 +1,8 @@ package org.lichess.compression.game; import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; -import java.util.HashSet; -import java.util.Set; +import java.util.Optional; +import java.util.OptionalInt; import java.util.regex.Pattern; import java.util.regex.Matcher; @@ -21,13 +19,31 @@ protected MoveList initialValue() { } }; + private final OpeningTrie openingTrie = OpeningTrie.mostCommonOpenings(); + public byte[] encode(String pgnMoves[]) { BitWriter writer = new BitWriter(); + Optional longestCommonOpening = openingTrie.findLongestCommonOpening(pgnMoves); + longestCommonOpening.ifPresentOrElse( + opening -> { + writer.writeBits(1, 1); + writer.writeBits(openingTrie.get(opening), openingTrie.getBitVectorLength()); + }, + () -> writer.writeBits(0, 1)); + + long numPliesLongestCommonOpening = longestCommonOpening + .map(opening -> opening + .chars() + .filter(c -> c == ' ') + .count()) + .orElse(0L); + Board board = new Board(); MoveList legals = moveList.get(); - for (String pgnMove: pgnMoves) { + for (int ply = 0; ply < pgnMoves.length; ply++) { + String pgnMove = pgnMoves[ply]; // Parse SAN. SAN sanMove = SANParser.parse(pgnMove, board); if (sanMove == null) return null; @@ -35,28 +51,39 @@ public byte[] encode(String pgnMoves[]) { // Find index in legal moves. board.legalMoves(legals); legals.sort(); - - boolean foundMatch = false; - int size = legals.size(); - - for (int i = 0; i < size; i++) { + + OptionalInt correctIndex = findSanInLegalMoves(sanMove, legals); + if (correctIndex.isPresent()) { + int i = correctIndex.getAsInt(); Move legal = legals.get(i); - if (legal.role == sanMove.role() && legal.to == sanMove.to() && legal.promotion == sanMove.promotion() && Bitboard.contains(sanMove.from(), legal.from)) { - if (!foundMatch) { - // Encode and play. - Huffman.write(i, writer); - board.play(legal); - foundMatch = true; - } - else return null; - } + if (ply >= numPliesLongestCommonOpening) Huffman.write(i, writer); + board.play(legal); + } + else { + return null; } - - if (!foundMatch) return null; } return writer.toArray(); } + + private OptionalInt findSanInLegalMoves(SAN sanMove, MoveList legals) { + boolean foundMatch = false; + int size = legals.size(); + OptionalInt correctIndex = OptionalInt.empty(); + for (int i = 0; i < size; i++) { + Move legal = legals.get(i); + if (legal.role == sanMove.role() && legal.to == sanMove.to() && legal.promotion == sanMove.promotion() && Bitboard.contains(sanMove.from(), legal.from)) { + if (!foundMatch) { + // Encode and play. + foundMatch = true; + correctIndex = OptionalInt.of(i); + } + else return OptionalInt.empty(); + } + } + return correctIndex; + } public static class DecodeResult { public final String pgnMoves[]; @@ -78,6 +105,25 @@ public DecodeResult decode(byte input[], int plies) { BitReader reader = new BitReader(input); String output[] = new String[plies]; + + long numPliesDecodedOpening = 0L; + + if (reader.readBits(1) == 1) { + int code = reader.readBits(openingTrie.getBitVectorLength()); + Optional decodedOpening = openingTrie.getFirstOpeningMappingToCode(code); + decodedOpening.ifPresent(opening -> { + String moves[] = opening.split(" "); + for (int i = 0; i < Math.min(plies, moves.length); i++) { + output[i] = moves[i]; + } + }); + numPliesDecodedOpening = decodedOpening + .map(opening -> opening + .chars() + .filter(c -> c == ' ') + .count()) + .orElse(0L); + } Board board = new Board(); MoveList legals = moveList.get(); @@ -102,8 +148,16 @@ public DecodeResult decode(byte input[], int plies) { // Decode and play next move. if (i < plies) { legals.sort(); - Move move = legals.get(Huffman.read(reader)); - output[i] = move.san(legals); + Move move; + if (i >= numPliesDecodedOpening) { + move = legals.get(Huffman.read(reader)); + output[i] = move.san(legals); + } + else { + SAN sanMove = SANParser.parse(output[i], board); + int correctIndex = findSanInLegalMoves(sanMove, legals).getAsInt(); + move = legals.get(correctIndex); + } board.play(move); if (move.isZeroing()) lastZeroingPly = i; diff --git a/src/main/java/game/OpeningTrie.java b/src/main/java/game/OpeningTrie.java index f5c39e0..62af5ec 100644 --- a/src/main/java/game/OpeningTrie.java +++ b/src/main/java/game/OpeningTrie.java @@ -27,9 +27,14 @@ public static OpeningTrie mostCommonOpenings() { public int get(String opening) { return openingTrie.get(opening); } - - public Set keySet() { - return openingTrie.keySet(); + + public Optional getFirstOpeningMappingToCode(int code) { + for (String opening: openingTrie.keySet()) { + if (openingTrie.get(opening) == code) { + return Optional.of(opening); + } + } + return Optional.empty(); } public int getBitVectorLength() { diff --git a/src/test/scala/HuffmanPgnTest.scala b/src/test/scala/HuffmanPgnTest.scala index 865f1f5..73d7273 100644 --- a/src/test/scala/HuffmanPgnTest.scala +++ b/src/test/scala/HuffmanPgnTest.scala @@ -20,14 +20,6 @@ class HuffmanPgnTest extends Specification: pgnMoves must_== decoded.pgnMoves } - "stable format" in: - forall(v1 zip fixtures) { case (encoded, pgn) => - val pgnMoves = pgn.split(" ") - val encoder = Encoder() - val decoded = encoder.decode(base64ToBytes(encoded), pgnMoves.size) - pgnMoves must_== decoded.pgnMoves - } - "least surprise" in: val n = 22 val encoder = Encoder() @@ -301,121 +293,4 @@ class HuffmanPgnTest extends Specification: "d4 e6 c4 d5 Nf3 c6 Nc3 Bd6 e3 f5 Bd3 Nf6 Qc2 O-O O-O Bd7 c5 Bc7 b4 Be8 Ng5 Ne4 Nxe6 Qh4 Nxf8 Qxh2#", "e4 b6 d4 Bb7 Bd3 e6 c4 Bb4+ Nc3 Bxc3+ bxc3 h6 Nf3 Nf6 Qe2 O-O O-O d6 h3 Nbd7 a4 e5 Re1 a5 Nh2 Nh7 d5 Nc5 Bc2 Bc8 f4 Qh4 Rf1 Nf6 fxe5 dxe5 Nf3 Qg3 Kh1", "e4 d5 exd5 Qxd5 Nc3 Qd8 Bc4 Nf6 d3 Bg4 f3 Bf5 Be3 e6 Nge2 c6 Ng3 Bg6 Qd2 Bd6 Nce4 Nxe4 Nxe4 Bc7 Bb3 Ba5 c3 Bxe4 fxe4 O-O O-O-O b5 h4 Bb6 d4 Nd7 g4 c5 g5 cxd4 Bxd4 Bxd4 Qxd4 Nb8 Qe3 Qc7" - ) - - val v1 = List( - "7qasJezzPJK15lj9CbbYheEA63S9DE37qYM/HcONsibhbJM/2xJqSwr/nVAX79Rn3x/vsAA=", - "KjTb/Zzt6FTIF/lVyHjtbeOzYeV9uhNzDfuV/699pPx/1XWiwVs31MA=", - "Mp0orWLvti0lxmh6kBmGf5IqTYEAdXvgx/3Jnivwhju9A6ImWcvOcc9n1FmEwA==", - "MhU6x0SImzC1OgAhmyHHSZLcNtUGucvp9TLlpoA=", - "PDdknk9du7oA11Y1tRdCpolRK+yysDyJ9z1Q", - "s3sbOnTq9vX15Npv7x4fJ97xFroPTbOLG+n9Q3639s5WH/7BQA==", - "Hw15mn6XrBtZGTjK0A==", - "Ugpnwa0n6QjIy8kUOHvF4vWAfNWGLlSpu4AGDXj+CUAfbz9YqN7Jq1sqLU2rqQmcfA==", - "19Sn95fufWzCaFjfjA==", - "Hw3FxvG9IvO817llUSMRAfV5xvfz/7Ez4kfrQWMgfg1NZz1n1D9gW0AqLQ==", - "LM7AHuV0bWvXpOGmfCsWvct0pUMzO1AV0XTqwBX68pFIq0XP0rvp2g==", - "zkmxSlt9/tqJ03f9B/Lbv8WnSSTNFLf11Wuz8dxe1//QCb9wv4i1/3JwIZWzXWaTwgMK9vGUr/ZVqt91WbzrlUA=", - "CGtPQ+eYf80+X/0C63rNmndIuJCBKzcx5b4u4nm3ha8Ul3updJ5mjhqLG4eUexdgdHNLHYWqpOg=", - "k8XmH/XqWTUtzb0FfAEODSU9gT2plavcE2l1IS+2kEcMmOdTr4P22vtsvWFnPMz9Zf3Ly1mBM0VfUV4TK/ZCZzu3AA==", - "k+fO9m7ugAzYRzplfkRc++fc6BmXoIFCkQ9zO7c6", - "BUL1i68rpzjsWPUJ2Pdk92pZJ6nCGB72yZwpuLCz0C7bn9wXPruaw0gbdav0rZ1ffFWg6A==", - "LOthhPsUt3Z477iYLiHYfBdAEvKxfMyDjTPrr0K7AhTjndfDLSzmoMa8tqkb30g=", - "AnSG1kzU5Yq/3W1r8pc++W3e8G/rdkvOFn93x/v+rkwd0PU11u9ULwgHmeCdv3BHXteI712hWYNcoA==", - "PDfxJxP78de/6HhPgcrkATDkByNP67npuEF2FeGmmgiA", - "mArWBeET583tvuNqHEQkAbLGO4J/OeGnlzebr+lIgaBv7cA=", - "ty73VQUu24W1KDl7tqeOC+TKoueDkJ+WLfYnAkA=", - "MF7OrJjpv1PueNH5uAZ4958JYA==", - "KnCPQhSuzsnzxJbZrPH/mK3pkFuPLbPWc98A", - "ysrQlz6bg1S5bgjzeeXJQA==", - "LFb0KkXcNZ3f2PBtQhABf4A=", - "Bg1PYNwxwIj/tXo=", - "KmPn/CTPMXaQz7Uae8eQ4uevEMA=", - "A618/WLNgHe98/vso2VXG9HicZOPF3sqzyMg", - "kvv8yK3ZWdJ+Iw/Bbb+r1P9r7H0w3LUN/gza+Y7c9wRAHZA=", - "k/0760KrEmRDhIzLFWHxrVuiH9Kr3+50x038r7eBXSSkP99u68l7WrvrGTlFQf6QKoMIXXUdWNE7AA==", - "Andh9gQNgU0xiZBfIqcgy86PbN9q/+SAuig=", - "K+8IExxnDUMbfTwtmne8O0su", - "CVSUMTl6Sc8/JxJ+pfX1Xa7lah9meFtCcE9FwUA=", - "kDe8/E+orRd88dwxtGhpTW9ARh5rEb/mYc4gmoA=", - "LNob+KTfOVRolcRnunH82UEhJgrmfdm1znTvc+Bj8NIM1PQC1GHviouxfWOuL2gdrjoXyqS4", - "VeEdjtGlsxcoa8Utvm92IsOEa866aNNLKkLxsA==", - "qCefpoSA3lN73H4DrIi8nznXtZhWpe47p0iSzXItfUA=", - "Hw3Gq73PyY3AB+unnhf0ucss", - "kN+zTf+9SWT92zEowhgma9xPUYw=", - "PBf5IfZfEMt13fvnNv5H38D16TuLwbXtaevbTQ==", - "WGHCpp5fvgWYfrjTWMjJL8VKerZcArLrTuM12HsGwZ756ZZKwtz6OLf+Qdct0L7EveqUsA==", - "KPwAiyY70yvnGX5k+YV/2S7n/VpPi9aA", - "yCVgblV+5/46gWBj3m0/sxpu/kw2mIS118A=", - "LI2BEkK/7hW4MfwSJF6A", - "PDfxISLpH9w5P6PcHee9xw1ecXry8azxeIh/+MhwB+5iKMg=", - "AKXNwe8rYUQnjecT", - "Mijq//lj3oo9eBUDTsjcpBiZAnhnUgB7tu4A", - "KPzZxNGQT1m2uxXaT8vP57BM2Av+FPkDJoxyeA/00A==", - "KKlErsNbydzbX/cHneNuv2SepoijLP4Gl79+gA==", - "ijQARzN4ef+W+bKHatW6bfjv17zlvQoB7dL/+vg0jvcLgA==", - "Hw3/RL0zFev0EarLk7tLPO80aL0=", - "Ar8BUYsLNYtZ8NrZA8/24fP35eGc1r1t+1nluSNy5A==", - "Cc1+r2sEPuqnP64hvbaJANL98J6A", - "KMeJCkLZxEJA0vfbz905zbTT635tQhDf3+rg", - "PP2up0ynHt0htYcq6g==", - "t3q/4EMWf6sv5lPOqqKb4I+GgA==", - "wW+5xenkBqqSUBxw51HLWE/rnlVRT4+Bu+oW3I33qN1Q", - "FjvmdkNJVB5+ZBO/Nf5b4Uxzexnq5edsx8Q=", - "yrTf297tPr69zzvTWISECwPNwfgD4A==", - "k+bvxZIbt0+pHi14k996oAV+85eGH/GdzCbIcfcaV/D8k/fEctOPbA==", - "DGoG0zKWZ3Ri5UseardCAA==", - "yNGyvxLz6rDSYlDJxgWfgA==", - "AlLU3aquoXcZKTWrbo8hJWj7XP/hAA6+w958dn9g7uphyLQ=", - "AnSvMbff/5P/TQW75A==", - "PBf5IW1ElYqorh374xIv7ux2P9VkmXDA7Va/h1bMsZ3SKFeGgA==", - "AnTzvDYHVmTFtxHydu/Lk5/R09nkJDQ=", - "AncICtSWO5R+idYO", - "3LKlNwT2x3SA/CYnfbjy7NIBG+uA", - "BfkxwR9+wWh31do2pC7h8q0UHVH7PMny+KA=", - "zqzheaUYv1au7CqrC6wsSW2s5sduyr8H+CVj0A==", - "PDfxH171aqzx7y0S4PCb6pBTbe/ANIaTdQNE", - "And38kC6LaCaV9dzuwA=", - "PKX6DR2s9l8qbzZz61Zn797XGvrxshsFz90X9xBb37yb9ep6zlfxLfcaoNAnkA==", - "Hw3FMUvXQy/dXu2s53zuhEtcTXf/L/Sbj4VvmbL2fO3CQcHee6F+b+dpVve4", - "g1JW3bIVjsu9rz7XYKZw", - "PGobF3d9dE6jaGJP+yCEu4/aR8akFFy9/A==", - "Kn0wuuDGvJvHmuyxQQ/1x+HAO8UkcZjngA==", - "kDS9c7zX14f2YOa7LSctZcc=", - "Ux1gmtqcnDGFbj2m5uEdY0B7B+72GGdzdIhJn6oBaA==", - "LIpO1gr+zHwWm1oZ9k3NHFbX7YYLoA==", - "Hw15mlUuGWs52FMgbi2Yvmg5Ozu8QAm27/++feV2Nt6X9AA=", - "Hw3FHmesQ7pDTLDtujGKhNkGkXmsdhDMyRnh5cA=", - "PGsBef76/gAFdX35X7zII3VJOs4uYA==", - "Hw15muXlxnv/mwEfKIGTLPmq1XxK/8zA", - "PK38njqKyEf191+aZvDR72/lnF/8dzoBkn6w", - "Aqu5uYBJFv8cH6q7TUjQb/8RscA=", - "tbvq0pKw8Tzx/STLSbF/O4rP0loMSBOOaA==", - "k+fZcHe+tUTJaqve4V5x/9ap3TPtZ8+tgdUuwA==", - "yLDopokZvj0PPspQvBnxtK6xgB+8AA==", - "3cIv1EaJIPehs793eyvZ5VQ8Zk3LI/z/bQtjLOzg7X38sag=", - "K/7LAczy54Y4TVa+ROYn6Te8FIUzvFVZQ80G84nF3TV/0rGqxuSgf2qwdHA=", - "g15tDk7MXCB+RJJpSKXTU5mQT0rd7YA=", - "mE7/kser33E8CE1uut9fzQ/YuIeYrV5rMEMzQFv4bztZNgA=", - "ngW6+L9e7v9CaENOjMwrsImE/A==", - "qC/W53U/M5PmXjfyr08sfeYA", - "k+K/u9Xh5jwkDGkzLdbe+5+1SbPF3/4vZld0Ijj8zZE4F/53rml7GgA=", - "CXyx/+8NAXes0vnfG37yxKzsZOOcGP8F4Pg=", - "mSl6sd++fLz19Kjl78v5vnFugwA=", - "Aqu6BVSbVSeQl77Iw/9A", - "AncJDmtxgp+9rG1IYJki3A==", - "Gb5fqN92K1wXqTIAHat075BvSXYarXeHUwYg", - "HwRZVB+8EdSBwxO/gzJtnefuJvzikOAkk+JY6wGuu/Zu/od+w8/219zQAA==", - "g03g3QQ/JqZVa0zBYvmN6pCPo4piXKbAZFJ5z+5+qiA=", - "BTers9z+p1zbk+G99SNLW0A=", - "k+Te7N29ZINd882eyt4Z2flvRzHg3AbA", - "yNKyHpcbseyQ9JfUnydJ2nmfh1iScNlQLWudN++/rRBXFoCqZnNZmIlSFheA", - "ylZ7XEFp1gDUqZO4fsQ0DPFR8xWqmf/i6mveCeIu9/bz0A==", - "7P9qO6ilfsxp1Y9nwnl4ANJG6VfJ8tD1/nKGAKG64EL7t9EIIXXqlKA=", - "Albpi7O7qd0nDJ2QVpxky7SfzOwR+vIuDGbH2F3+qA==", - "k+GyV5v1e84dMcCE22afckIDmA==", - "AjRJW+QgSMR9fZwwbXHpXXA=", - "lJ/o9i7j3b+eVTb/jdx/YA==", - "MBXVjuQzk9ZbSKw/IzSfmL9/8WX+4bn+", - "Hw15XVdxZr3eLz6xem8XLy8NLfv1/u0n/U0ifPQ=" - ) + ) \ No newline at end of file From 0fdb4bde5cdb2656de38b893e8baab958be86c25 Mon Sep 17 00:00:00 2001 From: ErdoganSeref Date: Tue, 6 Aug 2024 17:57:54 +0200 Subject: [PATCH 9/9] Optimize imports Remove unused imports Replace wildcard import with specific imports --- src/main/java/game/Encoder.java | 4 ---- src/main/java/game/OpeningTrie.java | 6 +++++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/game/Encoder.java b/src/main/java/game/Encoder.java index 6463b23..58dc63f 100644 --- a/src/main/java/game/Encoder.java +++ b/src/main/java/game/Encoder.java @@ -3,10 +3,6 @@ import java.util.Arrays; import java.util.Optional; import java.util.OptionalInt; -import java.util.regex.Pattern; -import java.util.regex.Matcher; - -import java.nio.ByteBuffer; import org.lichess.compression.BitReader; import org.lichess.compression.BitWriter; diff --git a/src/main/java/game/OpeningTrie.java b/src/main/java/game/OpeningTrie.java index 62af5ec..63f09d8 100644 --- a/src/main/java/game/OpeningTrie.java +++ b/src/main/java/game/OpeningTrie.java @@ -6,7 +6,11 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.util.*; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; public class OpeningTrie { private final int bitVectorLength;