├── .gitignore ├── requirements.txt ├── spanish.png ├── LICENSE ├── README.md ├── spanish.dot ├── chessgraph.py └── spanish.svg /.gitignore: -------------------------------------------------------------------------------- 1 | node-*.svg 2 | chess.dot 3 | chess.svg 4 | chess.png 5 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | graphviz 2 | cairosvg 3 | requests 4 | chess 5 | -------------------------------------------------------------------------------- /spanish.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vondele/chessgraph/HEAD/spanish.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2023, Joost VandeVondele 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | 3. Neither the name of the copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # chessgraph 2 | 3 | A utility to create a graph of moves from a specified position. 4 | 5 | ## examples 6 | 7 | ![Spanish](spanish.png) 8 | 9 | This screenshot was generated using: 10 | 11 | ```bash 12 | python chessgraph.py --depth=8 --alpha=30 --beta=50 --concurrency 32 --source engine\ 13 | --engine stockfish --enginedepth 18 --boardstyle svg\ 14 | --position="r1bqkbnr/pppp1ppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R b KQkq - 0 1" 15 | firefox chess.svg 16 | ``` 17 | 18 | The [svg image](https://github.com/vondele/chessgraph/raw/main/spanish.svg), (this time generated with unicode chess pieces) 19 | contains tooltips and links to the online [Chess Cloud Database](https://chessdb.cn/queryc_en/) 20 | that can be queried to generate the graph. 21 | 22 | ## interpretation of the graph 23 | 24 | The graph shows possible moves (edges) from each position (nodes). 25 | Nodes in yellow are white to move, nodes in brown are black to move. 26 | The numbers shown in the node are the evaluation of the position (white point of view). 27 | Nodes with multiple available moves (several leaving edges) have a board shown. 28 | Edges that represent sub-optimal moves are shown dashed. 29 | The best variation (principal variation, PV) is shown with a thick solid line. 30 | 31 | ## more options 32 | 33 | More options are available to visualize a tree. For example, allowing a local chess engine for analysis, changing the depth, or using images for the boards. The shape of the tree (and the cost of generating it), is strongly affected by the alpha, beta, and depth parameters. Start at low depth, and narrow [alpha, beta] range. 34 | 35 | ``` 36 | usage: chessgraph.py [-h] [--position POSITION | --san SAN] [--alpha ALPHA | --ralpha RALPHA | --salpha SALPHA] [--beta BETA | --rbeta RBETA | --sbeta SBETA] [--depth DEPTH] 37 | [--concurrency CONCURRENCY] [--source {chessdb,lichess,engine}] [--lichessdb {masters,lichess}] [--engine ENGINE] [--enginedepth ENGINEDEPTH] 38 | [--enginemaxmoves ENGINEMAXMOVES] [--networkstyle {graph,tree}] [--boardstyle {unicode,svg,none}] [--boardedges BOARDEDGES] [--output OUTPUT] [--embed | --no-embed] 39 | [--purgecache | --no-purgecache] 40 | 41 | A utility to create a graph of moves from a specified chess position. 42 | 43 | options: 44 | -h, --help show this help message and exit 45 | --position POSITION FEN of the root position. (default: rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1) 46 | --san SAN Moves in SAN notation that lead to the root position. E.g. "1. g4". (default: None) 47 | --alpha ALPHA Lower bound on the score of variations to be followed (for white). (default: 0) 48 | --ralpha RALPHA Set ALPHA = EVAL * RALPHA , where EVAL is the eval of the root position. (default: None) 49 | --salpha SALPHA Set ALPHA = EVAL - SALPHA. (default: None) 50 | --beta BETA Lower bound on the score of variations to be followed (for black). (default: 15) 51 | --rbeta RBETA Set BETA = EVAL * RBETA. (default: None) 52 | --sbeta SBETA Set BETA = EVAL + SBETA. (default: None) 53 | --depth DEPTH Maximum depth (in plies) of a followed variation. (default: 6) 54 | --concurrency CONCURRENCY 55 | Number of cores to use for work / requests. (default: 8) 56 | --source {chessdb,lichess,engine} 57 | Use chessdb, lichess or an engine to score and rank moves. (default: chessdb) 58 | --lichessdb {masters,lichess} 59 | Which lichess database to access: masters, or lichess players. (default: masters) 60 | --engine ENGINE Name of the engine binary (with path as needed). (default: stockfish) 61 | --enginedepth ENGINEDEPTH 62 | Depth of the search used by the engine in evaluation. (default: 20) 63 | --enginemaxmoves ENGINEMAXMOVES 64 | Maximum number of moves (MultiPV) considered by the engine in evaluation. (default: 10) 65 | --networkstyle {graph,tree} 66 | Selects the representation of the network as a graph (shows transpositions, compact) or a tree (simpler to follow, extended). (default: graph) 67 | --boardstyle {unicode,svg,none} 68 | Which style to use to visualize a board. (default: unicode) 69 | --boardedges BOARDEDGES 70 | Minimum number of edges needed before a board is visualized in the node. (default: 3) 71 | --output OUTPUT, -o OUTPUT 72 | Name of the output file (image in .svg format). (default: chess.svg) 73 | --embed, --no-embed If the individual svg boards should be embedded in the final .svg image. Unfortunately URLs are not preserved. (default: False) 74 | --purgecache, --no-purgecache 75 | Do no use, and later overwrite, the cache file stored on disk (chessgraph.cache.pyc). (default: False) 76 | ``` 77 | 78 | [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) 79 | -------------------------------------------------------------------------------- /spanish.dot: -------------------------------------------------------------------------------- 1 | digraph { 2 | "r1bqkbnr/pppp1ppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R b KQkq -" -> "r1bqkb1r/pppp1ppp/2n2n2/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq -" [label="Nf6", color=burlywood4, penwidth=3, fontname="Helvetica-bold", style=solid] 3 | "r1bqkbnr/pppp1ppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R b KQkq -" -> "r1bqkbnr/1ppp1ppp/p1n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq -" [label="a6", color=burlywood4, penwidth=1, fontname="Helvectica", style=dashed] 4 | "r1bqkbnr/pppp1ppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R b KQkq -" -> "r1bqkbnr/pppp1ppp/8/1B2p3/3nP3/5N2/PPPP1PPP/RNBQK2R w KQkq -" [label="Nd4", color=burlywood4, penwidth=1, fontname="Helvectica", style=dashed] 5 | "r1bqkbnr/pppp1ppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R b KQkq -" -> "r1bqkbnr/pppp2pp/2n5/1B2pp2/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq -" [label="f5", color=burlywood4, penwidth=1, fontname="Helvectica", style=dashed] 6 | "r1bqkbnr/pppp1ppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R b KQkq -" -> "r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq -" [label="Be7", color=burlywood4, penwidth=1, fontname="Helvectica", style=dashed] 7 | "r1bqkb1r/pppp1ppp/2n2n2/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq -" -> "r1bqkb1r/pppp1ppp/2n2n2/1B2p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 b kq -" [label="O-O", color=gold, penwidth=3, fontname="Helvetica-bold", style=solid] 8 | "r1bqkb1r/pppp1ppp/2n2n2/1B2p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 b kq -" -> "r1bqkb1r/pppp1ppp/2n5/1B2p3/4n3/5N2/PPPP1PPP/RNBQ1RK1 w kq -" [label="Nxe4", color=burlywood4, penwidth=3, fontname="Helvetica-bold", style=solid] 9 | "r1bqkb1r/pppp1ppp/2n2n2/1B2p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 b kq -" -> "r1bqk2r/pppp1ppp/2n2n2/1Bb1p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 w kq -" [label="Bc5", color=burlywood4, penwidth=1, fontname="Helvectica", style=dashed] 10 | "r1bqkb1r/pppp1ppp/2n5/1B2p3/4n3/5N2/PPPP1PPP/RNBQ1RK1 w kq -" -> "r1bqkb1r/pppp1ppp/2n5/1B2p3/4n3/5N2/PPPP1PPP/RNBQR1K1 b kq -" [label="Re1", color=gold, penwidth=3, fontname="Helvetica-bold", style=solid] 11 | "r1bqkb1r/pppp1ppp/2n5/1B2p3/4n3/5N2/PPPP1PPP/RNBQR1K1 b kq -" -> "r1bqkb1r/pppp1ppp/2nn4/1B2p3/8/5N2/PPPP1PPP/RNBQR1K1 w kq -" [label="Nd6", color=burlywood4, penwidth=3, fontname="Helvetica-bold", style=solid] 12 | "r1bqkb1r/pppp1ppp/2nn4/1B2p3/8/5N2/PPPP1PPP/RNBQR1K1 w kq -" -> "r1bqkb1r/pppp1ppp/2nn4/1B2N3/8/8/PPPP1PPP/RNBQR1K1 b kq -" [label="Nxe5", color=gold, penwidth=3, fontname="Helvetica-bold", style=solid] 13 | "r1bqkb1r/pppp1ppp/2nn4/1B2N3/8/8/PPPP1PPP/RNBQR1K1 b kq -" -> "r1bqkb1r/pppp1ppp/3n4/1B2n3/8/8/PPPP1PPP/RNBQR1K1 w kq -" [label="Nxe5", color=burlywood4, penwidth=3, fontname="Helvetica-bold", style=solid] 14 | "r1bqkb1r/pppp1ppp/2nn4/1B2N3/8/8/PPPP1PPP/RNBQR1K1 b kq -" -> "r1bqk2r/ppppbppp/2nn4/1B2N3/8/8/PPPP1PPP/RNBQR1K1 w kq -" [label="Be7", color=burlywood4, penwidth=3, fontname="Helvetica-bold", style=solid] 15 | "r1bqkb1r/pppp1ppp/3n4/1B2n3/8/8/PPPP1PPP/RNBQR1K1 w kq -" [fontname="Courier", label="♜ · ♝ ♛ ♚ ♝ · ♜ 16 | ♟ ♟ ♟ ♟ · ♟ ♟ ♟ 17 | · · · ♞ · · · · 18 | · ♗ · · ♞ · · · 19 | · · · · · · · · 20 | · · · · · · · · 21 | ♙ ♙ ♙ ♙ · ♙ ♙ ♙ 22 | ♖ ♘ ♗ ♕ ♖ · ♔ ·", color=gold, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqkb1r/pppp1ppp/3n4/1B2n3/8/8/PPPP1PPP/RNBQR1K1%20w%20kq%20-", penwidth=3] 23 | "r1bqk2r/ppppbppp/2nn4/1B2N3/8/8/PPPP1PPP/RNBQR1K1 w kq -" [fontname="Courier", label="♜ · ♝ ♛ ♚ · · ♜ 24 | ♟ ♟ ♟ ♟ ♝ ♟ ♟ ♟ 25 | · · ♞ ♞ · · · · 26 | · ♗ · · ♘ · · · 27 | · · · · · · · · 28 | · · · · · · · · 29 | ♙ ♙ ♙ ♙ · ♙ ♙ ♙ 30 | ♖ ♘ ♗ ♕ ♖ · ♔ ·", color=gold, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqk2r/ppppbppp/2nn4/1B2N3/8/8/PPPP1PPP/RNBQR1K1%20w%20kq%20-", penwidth=3] 31 | "r1bqkb1r/pppp1ppp/2nn4/1B2N3/8/8/PPPP1PPP/RNBQR1K1 b kq -" [label="38", color=burlywood4, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqkb1r/pppp1ppp/2nn4/1B2N3/8/8/PPPP1PPP/RNBQR1K1%20b%20kq%20-", penwidth=3] 32 | "r1bqkb1r/pppp1ppp/2nn4/1B2p3/8/5N2/PPPP1PPP/RNBQR1K1 w kq -" [label="32", color=gold, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqkb1r/pppp1ppp/2nn4/1B2p3/8/5N2/PPPP1PPP/RNBQR1K1%20w%20kq%20-", penwidth=3] 33 | "r1bqkb1r/pppp1ppp/2n5/1B2p3/4n3/5N2/PPPP1PPP/RNBQR1K1 b kq -" [label="31", color=burlywood4, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqkb1r/pppp1ppp/2n5/1B2p3/4n3/5N2/PPPP1PPP/RNBQR1K1%20b%20kq%20-", penwidth=3] 34 | "r1bqkb1r/pppp1ppp/2n5/1B2p3/4n3/5N2/PPPP1PPP/RNBQ1RK1 w kq -" [label="37", color=gold, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqkb1r/pppp1ppp/2n5/1B2p3/4n3/5N2/PPPP1PPP/RNBQ1RK1%20w%20kq%20-", penwidth=3] 35 | "r1bqk2r/pppp1ppp/2n2n2/1Bb1p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 w kq -" -> "r1bqk2r/pppp1ppp/2n2n2/1Bb1N3/4P3/8/PPPP1PPP/RNBQ1RK1 b kq -" [label="Nxe5", color=gold, penwidth=1, fontname="Helvectica", style=solid] 36 | "r1bqk2r/pppp1ppp/2n2n2/1Bb1p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 w kq -" -> "r1bqk2r/pppp1ppp/2n2n2/1Bb1p3/4P3/2P2N2/PP1P1PPP/RNBQ1RK1 b kq -" [label="c3", color=gold, penwidth=1, fontname="Helvectica", style=solid] 37 | "r1bqk2r/pppp1ppp/2n2n2/1Bb1p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 w kq -" -> "r1bqk2r/pppp1ppp/2n2n2/1Bb1p3/4P3/2N2N2/PPPP1PPP/R1BQ1RK1 b kq -" [label="Nc3", color=gold, penwidth=1, fontname="Helvectica", style=dashed] 38 | "r1bqk2r/pppp1ppp/2n2n2/1Bb1N3/4P3/8/PPPP1PPP/RNBQ1RK1 b kq -" [label="51", color=burlywood4, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqk2r/pppp1ppp/2n2n2/1Bb1N3/4P3/8/PPPP1PPP/RNBQ1RK1%20b%20kq%20-", penwidth=1] 39 | "r1bqk2r/pppp1ppp/2n2n2/1Bb1p3/4P3/2P2N2/PP1P1PPP/RNBQ1RK1 b kq -" -> "r1bq1rk1/pppp1ppp/2n2n2/1Bb1p3/4P3/2P2N2/PP1P1PPP/RNBQ1RK1 w - -" [label="O-O", color=burlywood4, penwidth=1, fontname="Helvectica", style=solid] 40 | "r1bqk2r/pppp1ppp/2n2n2/1Bb1p3/4P3/2P2N2/PP1P1PPP/RNBQ1RK1 b kq -" -> "r1bqk2r/pppp1ppp/1bn2n2/1B2p3/4P3/2P2N2/PP1P1PPP/RNBQ1RK1 w kq -" [label="Bb6", color=burlywood4, penwidth=1, fontname="Helvectica", style=dashed] 41 | "r1bq1rk1/pppp1ppp/2n2n2/1Bb1p3/4P3/2P2N2/PP1P1PPP/RNBQ1RK1 w - -" -> "r1bq1rk1/pppp1ppp/2n2n2/1Bb1p3/3PP3/2P2N2/PP3PPP/RNBQ1RK1 b - -" [label="d4", color=gold, penwidth=1, fontname="Helvectica", style=solid] 42 | "r1bq1rk1/pppp1ppp/2n2n2/1Bb1p3/3PP3/2P2N2/PP3PPP/RNBQ1RK1 b - -" [label="48", color=burlywood4, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bq1rk1/pppp1ppp/2n2n2/1Bb1p3/3PP3/2P2N2/PP3PPP/RNBQ1RK1%20b%20-%20-", penwidth=1] 43 | "r1bq1rk1/pppp1ppp/2n2n2/1Bb1p3/4P3/2P2N2/PP1P1PPP/RNBQ1RK1 w - -" [label="47", color=gold, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bq1rk1/pppp1ppp/2n2n2/1Bb1p3/4P3/2P2N2/PP1P1PPP/RNBQ1RK1%20w%20-%20-", penwidth=1] 44 | "r1bqk2r/pppp1ppp/1bn2n2/1B2p3/4P3/2P2N2/PP1P1PPP/RNBQ1RK1 w kq -" [label="67", color=gold, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqk2r/pppp1ppp/1bn2n2/1B2p3/4P3/2P2N2/PP1P1PPP/RNBQ1RK1%20w%20kq%20-", penwidth=1] 45 | "r1bqk2r/pppp1ppp/2n2n2/1Bb1p3/4P3/2P2N2/PP1P1PPP/RNBQ1RK1 b kq -" [label="38", color=burlywood4, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqk2r/pppp1ppp/2n2n2/1Bb1p3/4P3/2P2N2/PP1P1PPP/RNBQ1RK1%20b%20kq%20-", penwidth=1] 46 | "r1bqk2r/pppp1ppp/2n2n2/1Bb1p3/4P3/2N2N2/PPPP1PPP/R1BQ1RK1 b kq -" [label="7", color=burlywood4, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqk2r/pppp1ppp/2n2n2/1Bb1p3/4P3/2N2N2/PPPP1PPP/R1BQ1RK1%20b%20kq%20-", penwidth=1] 47 | "r1bqk2r/pppp1ppp/2n2n2/1Bb1p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 w kq -" [fontname="Courier", label="♜ · ♝ ♛ ♚ · · ♜ 48 | ♟ ♟ ♟ ♟ · ♟ ♟ ♟ 49 | · · ♞ · · ♞ · · 50 | · ♗ ♝ · ♟ · · · 51 | · · · · ♙ · · · 52 | · · · · · ♘ · · 53 | ♙ ♙ ♙ ♙ · ♙ ♙ ♙ 54 | ♖ ♘ ♗ ♕ · ♖ ♔ ·", color=gold, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqk2r/pppp1ppp/2n2n2/1Bb1p3/4P3/5N2/PPPP1PPP/RNBQ1RK1%20w%20kq%20-", penwidth=1] 55 | "r1bqkb1r/pppp1ppp/2n2n2/1B2p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 b kq -" [label="24", color=burlywood4, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqkb1r/pppp1ppp/2n2n2/1B2p3/4P3/5N2/PPPP1PPP/RNBQ1RK1%20b%20kq%20-", penwidth=3] 56 | "r1bqkb1r/pppp1ppp/2n2n2/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq -" [label="31", color=gold, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqkb1r/pppp1ppp/2n2n2/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R%20w%20KQkq%20-", penwidth=3] 57 | "r1bqkbnr/1ppp1ppp/p1n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq -" -> "r1bqkbnr/1ppp1ppp/p1n5/4p3/B3P3/5N2/PPPP1PPP/RNBQK2R b KQkq -" [label="Ba4", color=gold, penwidth=1, fontname="Helvectica", style=solid] 58 | "r1bqkbnr/1ppp1ppp/p1n5/4p3/B3P3/5N2/PPPP1PPP/RNBQK2R b KQkq -" -> "r1bqkbnr/2pp1ppp/p1n5/1p2p3/B3P3/5N2/PPPP1PPP/RNBQK2R w KQkq -" [label="b5", color=burlywood4, penwidth=1, fontname="Helvectica", style=solid] 59 | "r1bqkbnr/2pp1ppp/p1n5/1p2p3/B3P3/5N2/PPPP1PPP/RNBQK2R w KQkq -" -> "r1bqkbnr/2pp1ppp/p1n5/1p2p3/4P3/1B3N2/PPPP1PPP/RNBQK2R b KQkq -" [label="Bb3", color=gold, penwidth=1, fontname="Helvectica", style=solid] 60 | "r1bqkbnr/2pp1ppp/p1n5/1p2p3/4P3/1B3N2/PPPP1PPP/RNBQK2R b KQkq -" [label="50", color=burlywood4, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqkbnr/2pp1ppp/p1n5/1p2p3/4P3/1B3N2/PPPP1PPP/RNBQK2R%20b%20KQkq%20-", penwidth=1] 61 | "r1bqkbnr/2pp1ppp/p1n5/1p2p3/B3P3/5N2/PPPP1PPP/RNBQK2R w KQkq -" [label="50", color=gold, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqkbnr/2pp1ppp/p1n5/1p2p3/B3P3/5N2/PPPP1PPP/RNBQK2R%20w%20KQkq%20-", penwidth=1] 62 | "r1bqkbnr/1ppp1ppp/p1n5/4p3/B3P3/5N2/PPPP1PPP/RNBQK2R b KQkq -" [label="49", color=burlywood4, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqkbnr/1ppp1ppp/p1n5/4p3/B3P3/5N2/PPPP1PPP/RNBQK2R%20b%20KQkq%20-", penwidth=1] 63 | "r1bqkbnr/1ppp1ppp/p1n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq -" [label="42", color=gold, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqkbnr/1ppp1ppp/p1n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R%20w%20KQkq%20-", penwidth=1] 64 | "r1bqkbnr/pppp1ppp/8/1B2p3/3nP3/5N2/PPPP1PPP/RNBQK2R w KQkq -" -> "r1bqkbnr/pppp1ppp/8/1B2p3/3NP3/8/PPPP1PPP/RNBQK2R b KQkq -" [label="Nxd4", color=gold, penwidth=1, fontname="Helvectica", style=solid] 65 | "r1bqkbnr/pppp1ppp/8/1B2p3/3nP3/5N2/PPPP1PPP/RNBQK2R w KQkq -" -> "r1bqkbnr/pppp1ppp/8/4p3/2BnP3/5N2/PPPP1PPP/RNBQK2R b KQkq -" [label="Bc4", color=gold, penwidth=1, fontname="Helvectica", style=dashed] 66 | "r1bqkbnr/pppp1ppp/8/1B2p3/3NP3/8/PPPP1PPP/RNBQK2R b KQkq -" [label="59", color=burlywood4, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqkbnr/pppp1ppp/8/1B2p3/3NP3/8/PPPP1PPP/RNBQK2R%20b%20KQkq%20-", penwidth=1] 67 | "r1bqkbnr/pppp1ppp/8/4p3/2BnP3/5N2/PPPP1PPP/RNBQK2R b KQkq -" -> "r1bqkbnr/pppp1ppp/8/4p3/2B1P3/5n2/PPPP1PPP/RNBQK2R w KQkq -" [label="Nxf3+", color=burlywood4, penwidth=1, fontname="Helvectica", style=solid] 68 | "r1bqkbnr/pppp1ppp/8/4p3/2B1P3/5n2/PPPP1PPP/RNBQK2R w KQkq -" -> "r1bqkbnr/pppp1ppp/8/4p3/2B1P3/5Q2/PPPP1PPP/RNB1K2R b KQkq -" [label="Qxf3", color=gold, penwidth=1, fontname="Helvectica", style=solid] 69 | "r1bqkbnr/pppp1ppp/8/4p3/2B1P3/5Q2/PPPP1PPP/RNB1K2R b KQkq -" [label="22", color=burlywood4, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqkbnr/pppp1ppp/8/4p3/2B1P3/5Q2/PPPP1PPP/RNB1K2R%20b%20KQkq%20-", penwidth=1] 70 | "r1bqkbnr/pppp1ppp/8/4p3/2B1P3/5n2/PPPP1PPP/RNBQK2R w KQkq -" [label="33", color=gold, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqkbnr/pppp1ppp/8/4p3/2B1P3/5n2/PPPP1PPP/RNBQK2R%20w%20KQkq%20-", penwidth=1] 71 | "r1bqkbnr/pppp1ppp/8/4p3/2BnP3/5N2/PPPP1PPP/RNBQK2R b KQkq -" [label="44", color=burlywood4, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqkbnr/pppp1ppp/8/4p3/2BnP3/5N2/PPPP1PPP/RNBQK2R%20b%20KQkq%20-", penwidth=1] 72 | "r1bqkbnr/pppp1ppp/8/1B2p3/3nP3/5N2/PPPP1PPP/RNBQK2R w KQkq -" [label="57", color=gold, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqkbnr/pppp1ppp/8/1B2p3/3nP3/5N2/PPPP1PPP/RNBQK2R%20w%20KQkq%20-", penwidth=1] 73 | "r1bqkbnr/pppp2pp/2n5/1B2pp2/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq -" -> "r1bqkbnr/pppp2pp/2n5/1B2pp2/4P3/2N2N2/PPPP1PPP/R1BQK2R b KQkq -" [label="Nc3", color=gold, penwidth=1, fontname="Helvectica", style=solid] 74 | "r1bqkbnr/pppp2pp/2n5/1B2pp2/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq -" -> "r1bqkbnr/pppp2pp/2n5/1B2pp2/4P3/3P1N2/PPP2PPP/RNBQK2R b KQkq -" [label="d3", color=gold, penwidth=1, fontname="Helvectica", style=dashed] 75 | "r1bqkbnr/pppp2pp/2n5/1B2pp2/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq -" -> "r1bqkbnr/pppp2pp/2n5/1B2pp2/3PP3/5N2/PPP2PPP/RNBQK2R b KQkq -" [label="d4", color=gold, penwidth=1, fontname="Helvectica", style=dashed] 76 | "r1bqkbnr/pppp2pp/2n5/1B2pp2/4P3/2N2N2/PPPP1PPP/R1BQK2R b KQkq -" [label="68", color=burlywood4, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqkbnr/pppp2pp/2n5/1B2pp2/4P3/2N2N2/PPPP1PPP/R1BQK2R%20b%20KQkq%20-", penwidth=1] 77 | "r1bqkbnr/pppp2pp/2n5/1B2pp2/4P3/3P1N2/PPP2PPP/RNBQK2R b KQkq -" -> "r1bqkbnr/pppp2pp/2n5/1B2p3/4p3/3P1N2/PPP2PPP/RNBQK2R w KQkq -" [label="fxe4", color=burlywood4, penwidth=1, fontname="Helvectica", style=solid] 78 | "r1bqkbnr/pppp2pp/2n5/1B2p3/4p3/3P1N2/PPP2PPP/RNBQK2R w KQkq -" -> "r1bqkbnr/pppp2pp/2n5/1B2p3/4P3/5N2/PPP2PPP/RNBQK2R b KQkq -" [label="dxe4", color=gold, penwidth=1, fontname="Helvectica", style=solid] 79 | "r1bqkbnr/pppp2pp/2n5/1B2p3/4P3/5N2/PPP2PPP/RNBQK2R b KQkq -" [label="49", color=burlywood4, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqkbnr/pppp2pp/2n5/1B2p3/4P3/5N2/PPP2PPP/RNBQK2R%20b%20KQkq%20-", penwidth=1] 80 | "r1bqkbnr/pppp2pp/2n5/1B2p3/4p3/3P1N2/PPP2PPP/RNBQK2R w KQkq -" [label="64", color=gold, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqkbnr/pppp2pp/2n5/1B2p3/4p3/3P1N2/PPP2PPP/RNBQK2R%20w%20KQkq%20-", penwidth=1] 81 | "r1bqkbnr/pppp2pp/2n5/1B2pp2/4P3/3P1N2/PPP2PPP/RNBQK2R b KQkq -" [label="44", color=burlywood4, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqkbnr/pppp2pp/2n5/1B2pp2/4P3/3P1N2/PPP2PPP/RNBQK2R%20b%20KQkq%20-", penwidth=1] 82 | "r1bqkbnr/pppp2pp/2n5/1B2pp2/3PP3/5N2/PPP2PPP/RNBQK2R b KQkq -" -> "r1bqkbnr/pppp2pp/2n5/1B2p3/3Pp3/5N2/PPP2PPP/RNBQK2R w KQkq -" [label="fxe4", color=burlywood4, penwidth=1, fontname="Helvectica", style=solid] 83 | "r1bqkbnr/pppp2pp/2n5/1B2p3/3Pp3/5N2/PPP2PPP/RNBQK2R w KQkq -" [label="8", color=gold, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqkbnr/pppp2pp/2n5/1B2p3/3Pp3/5N2/PPP2PPP/RNBQK2R%20w%20KQkq%20-", penwidth=1] 84 | "r1bqkbnr/pppp2pp/2n5/1B2pp2/3PP3/5N2/PPP2PPP/RNBQK2R b KQkq -" [label="15", color=burlywood4, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqkbnr/pppp2pp/2n5/1B2pp2/3PP3/5N2/PPP2PPP/RNBQK2R%20b%20KQkq%20-", penwidth=1] 85 | "r1bqkbnr/pppp2pp/2n5/1B2pp2/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq -" [fontname="Courier", label="♜ · ♝ ♛ ♚ ♝ ♞ ♜ 86 | ♟ ♟ ♟ ♟ · · ♟ ♟ 87 | · · ♞ · · · · · 88 | · ♗ · · ♟ ♟ · · 89 | · · · · ♙ · · · 90 | · · · · · ♘ · · 91 | ♙ ♙ ♙ ♙ · ♙ ♙ ♙ 92 | ♖ ♘ ♗ ♕ ♔ · · ♖", color=gold, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqkbnr/pppp2pp/2n5/1B2pp2/4P3/5N2/PPPP1PPP/RNBQK2R%20w%20KQkq%20-", penwidth=1] 93 | "r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq -" -> "r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 b kq -" [label="O-O", color=gold, penwidth=1, fontname="Helvectica", style=solid] 94 | "r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq -" -> "r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/3P1N2/PPP2PPP/RNBQK2R b KQkq -" [label="d3", color=gold, penwidth=1, fontname="Helvectica", style=dashed] 95 | "r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq -" -> "r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/2N2N2/PPPP1PPP/R1BQK2R b KQkq -" [label="Nc3", color=gold, penwidth=1, fontname="Helvectica", style=dashed] 96 | "r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq -" -> "r1bqk1nr/ppppbppp/2n5/4p3/B3P3/5N2/PPPP1PPP/RNBQK2R b KQkq -" [label="Ba4", color=gold, penwidth=1, fontname="Helvectica", style=dashed] 97 | "r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq -" -> "r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/2P2N2/PP1P1PPP/RNBQK2R b KQkq -" [label="c3", color=gold, penwidth=1, fontname="Helvectica", style=dashed] 98 | "r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq -" -> "r1bqk1nr/ppppbppp/2n5/1B2p3/3PP3/5N2/PPP2PPP/RNBQK2R b KQkq -" [label="d4", color=gold, penwidth=1, fontname="Helvectica", style=dashed] 99 | "r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq -" -> "r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/5N2/PPPPQPPP/RNB1K2R b KQkq -" [label="Qe2", color=gold, penwidth=1, fontname="Helvectica", style=dashed] 100 | "r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 b kq -" -> "r1bqk1nr/1pppbppp/p1n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 w kq -" [label="a6", color=burlywood4, penwidth=1, fontname="Helvectica", style=solid] 101 | "r1bqk1nr/1pppbppp/p1n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 w kq -" -> "r1bqk1nr/1pppbppp/p1B5/4p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 b kq -" [label="Bxc6", color=gold, penwidth=1, fontname="Helvectica", style=solid] 102 | "r1bqk1nr/1pppbppp/p1n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 w kq -" -> "r1bqk1nr/1pppbppp/p1n5/4p3/B3P3/5N2/PPPP1PPP/RNBQ1RK1 b kq -" [label="Ba4", color=gold, penwidth=1, fontname="Helvectica", style=dashed] 103 | "r1bqk1nr/1pppbppp/p1B5/4p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 b kq -" -> "r1bqk1nr/1pp1bppp/p1p5/4p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 w kq -" [label="dxc6", color=burlywood4, penwidth=1, fontname="Helvectica", style=solid] 104 | "r1bqk1nr/1pp1bppp/p1p5/4p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 w kq -" [label="37", color=gold, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqk1nr/1pp1bppp/p1p5/4p3/4P3/5N2/PPPP1PPP/RNBQ1RK1%20w%20kq%20-", penwidth=1] 105 | "r1bqk1nr/1pppbppp/p1B5/4p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 b kq -" [label="49", color=burlywood4, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqk1nr/1pppbppp/p1B5/4p3/4P3/5N2/PPPP1PPP/RNBQ1RK1%20b%20kq%20-", penwidth=1] 106 | "r1bqk1nr/1pppbppp/p1n5/4p3/B3P3/5N2/PPPP1PPP/RNBQ1RK1 b kq -" [label="42", color=burlywood4, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqk1nr/1pppbppp/p1n5/4p3/B3P3/5N2/PPPP1PPP/RNBQ1RK1%20b%20kq%20-", penwidth=1] 107 | "r1bqk1nr/1pppbppp/p1n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 w kq -" [label="73", color=gold, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqk1nr/1pppbppp/p1n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQ1RK1%20w%20kq%20-", penwidth=1] 108 | "r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 b kq -" [label="48", color=burlywood4, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQ1RK1%20b%20kq%20-", penwidth=1] 109 | "r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/3P1N2/PPP2PPP/RNBQK2R b KQkq -" -> "r1bqk1nr/ppp1bppp/2np4/1B2p3/4P3/3P1N2/PPP2PPP/RNBQK2R w KQkq -" [label="d6", color=burlywood4, penwidth=1, fontname="Helvectica", style=solid] 110 | "r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/3P1N2/PPP2PPP/RNBQK2R b KQkq -" -> "r1bqk1nr/pppp1ppp/2n2b2/1B2p3/4P3/3P1N2/PPP2PPP/RNBQK2R w KQkq -" [label="Bf6", color=burlywood4, penwidth=1, fontname="Helvectica", style=dashed] 111 | "r1bqk1nr/ppp1bppp/2np4/1B2p3/4P3/3P1N2/PPP2PPP/RNBQK2R w KQkq -" -> "r1bqk1nr/ppp1bppp/2np4/1B2p3/4P3/3P1N2/PPP2PPP/RNBQ1RK1 b kq -" [label="O-O", color=gold, penwidth=1, fontname="Helvectica", style=solid] 112 | "r1bqk1nr/ppp1bppp/2np4/1B2p3/4P3/3P1N2/PPP2PPP/RNBQ1RK1 b kq -" [label="11", color=burlywood4, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqk1nr/ppp1bppp/2np4/1B2p3/4P3/3P1N2/PPP2PPP/RNBQ1RK1%20b%20kq%20-", penwidth=1] 113 | "r1bqk1nr/ppp1bppp/2np4/1B2p3/4P3/3P1N2/PPP2PPP/RNBQK2R w KQkq -" [label="31", color=gold, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqk1nr/ppp1bppp/2np4/1B2p3/4P3/3P1N2/PPP2PPP/RNBQK2R%20w%20KQkq%20-", penwidth=1] 114 | "r1bqk1nr/pppp1ppp/2n2b2/1B2p3/4P3/3P1N2/PPP2PPP/RNBQK2R w KQkq -" [label="50", color=gold, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqk1nr/pppp1ppp/2n2b2/1B2p3/4P3/3P1N2/PPP2PPP/RNBQK2R%20w%20KQkq%20-", penwidth=1] 115 | "r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/3P1N2/PPP2PPP/RNBQK2R b KQkq -" [label="31", color=burlywood4, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/3P1N2/PPP2PPP/RNBQK2R%20b%20KQkq%20-", penwidth=1] 116 | "r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/2N2N2/PPPP1PPP/R1BQK2R b KQkq -" -> "r1bqk2r/ppppbppp/2n2n2/1B2p3/4P3/2N2N2/PPPP1PPP/R1BQK2R w KQkq -" [label="Nf6", color=burlywood4, penwidth=1, fontname="Helvectica", style=solid] 117 | "r1bqk2r/ppppbppp/2n2n2/1B2p3/4P3/2N2N2/PPPP1PPP/R1BQK2R w KQkq -" [label="41", color=gold, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqk2r/ppppbppp/2n2n2/1B2p3/4P3/2N2N2/PPPP1PPP/R1BQK2R%20w%20KQkq%20-", penwidth=1] 118 | "r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/2N2N2/PPPP1PPP/R1BQK2R b KQkq -" [label="37", color=burlywood4, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/2N2N2/PPPP1PPP/R1BQK2R%20b%20KQkq%20-", penwidth=1] 119 | "r1bqk1nr/ppppbppp/2n5/4p3/B3P3/5N2/PPPP1PPP/RNBQK2R b KQkq -" -> "r1bqk1nr/ppppb1pp/2n5/4pp2/B3P3/5N2/PPPP1PPP/RNBQK2R w KQkq -" [label="f5", color=burlywood4, penwidth=1, fontname="Helvectica", style=solid] 120 | "r1bqk1nr/ppppb1pp/2n5/4pp2/B3P3/5N2/PPPP1PPP/RNBQK2R w KQkq -" [label="33", color=gold, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqk1nr/ppppb1pp/2n5/4pp2/B3P3/5N2/PPPP1PPP/RNBQK2R%20w%20KQkq%20-", penwidth=1] 121 | "r1bqk1nr/ppppbppp/2n5/4p3/B3P3/5N2/PPPP1PPP/RNBQK2R b KQkq -" [label="26", color=burlywood4, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqk1nr/ppppbppp/2n5/4p3/B3P3/5N2/PPPP1PPP/RNBQK2R%20b%20KQkq%20-", penwidth=1] 122 | "r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/2P2N2/PP1P1PPP/RNBQK2R b KQkq -" -> "r1bqk1nr/ppppb1pp/2n5/1B2pp2/4P3/2P2N2/PP1P1PPP/RNBQK2R w KQkq -" [label="f5", color=burlywood4, penwidth=1, fontname="Helvectica", style=solid] 123 | "r1bqk1nr/ppppb1pp/2n5/1B2pp2/4P3/2P2N2/PP1P1PPP/RNBQK2R w KQkq -" [label="28", color=gold, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqk1nr/ppppb1pp/2n5/1B2pp2/4P3/2P2N2/PP1P1PPP/RNBQK2R%20w%20KQkq%20-", penwidth=1] 124 | "r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/2P2N2/PP1P1PPP/RNBQK2R b KQkq -" [label="15", color=burlywood4, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/2P2N2/PP1P1PPP/RNBQK2R%20b%20KQkq%20-", penwidth=1] 125 | "r1bqk1nr/ppppbppp/2n5/1B2p3/3PP3/5N2/PPP2PPP/RNBQK2R b KQkq -" [label="26", color=burlywood4, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqk1nr/ppppbppp/2n5/1B2p3/3PP3/5N2/PPP2PPP/RNBQK2R%20b%20KQkq%20-", penwidth=1] 126 | "r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/5N2/PPPPQPPP/RNB1K2R b KQkq -" [label="30", color=burlywood4, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/5N2/PPPPQPPP/RNB1K2R%20b%20KQkq%20-", penwidth=1] 127 | "r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq -" [fontname="Courier", label="♜ · ♝ ♛ ♚ · ♞ ♜ 128 | ♟ ♟ ♟ ♟ ♝ ♟ ♟ ♟ 129 | · · ♞ · · · · · 130 | · ♗ · · ♟ · · · 131 | · · · · ♙ · · · 132 | · · · · · ♘ · · 133 | ♙ ♙ ♙ ♙ · ♙ ♙ ♙ 134 | ♖ ♘ ♗ ♕ ♔ · · ♖", color=gold, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R%20w%20KQkq%20-", penwidth=1] 135 | "r1bqkbnr/pppp1ppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R b KQkq -" [fontname="Courier", label="♜ · ♝ ♛ ♚ ♝ ♞ ♜ 136 | ♟ ♟ ♟ ♟ · ♟ ♟ ♟ 137 | · · ♞ · · · · · 138 | · ♗ · · ♟ · · · 139 | · · · · ♙ · · · 140 | · · · · · ♘ · · 141 | ♙ ♙ ♙ ♙ · ♙ ♙ ♙ 142 | ♖ ♘ ♗ ♕ ♔ · · ♖", color=burlywood4, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqkbnr/pppp1ppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R%20b%20KQkq%20-", penwidth=3] 143 | "r1bqkbnr/pppp1ppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R b KQkq -" [fontname="Courier", label="♜ · ♝ ♛ ♚ ♝ ♞ ♜ 144 | ♟ ♟ ♟ ♟ · ♟ ♟ ♟ 145 | · · ♞ · · · · · 146 | · ♗ · · ♟ · · · 147 | · · · · ♙ · · · 148 | · · · · · ♘ · · 149 | ♙ ♙ ♙ ♙ · ♙ ♙ ♙ 150 | ♖ ♘ ♗ ♕ ♔ · · ♖", color=burlywood4, shape=box, URL="https://www.chessdb.cn/queryc_en/?r1bqkbnr/pppp1ppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R%20b%20KQkq%20-", penwidth=3] 151 | } 152 | -------------------------------------------------------------------------------- /chessgraph.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import pickle 3 | import platform 4 | import argparse 5 | import chess 6 | import chess.engine 7 | import chess.svg 8 | import math 9 | import sys 10 | import concurrent.futures 11 | import multiprocessing 12 | import hashlib 13 | import cairosvg 14 | import graphviz 15 | from os.path import exists 16 | from urllib import parse 17 | 18 | 19 | class ChessGraph: 20 | def __init__( 21 | self, 22 | networkstyle, 23 | depth, 24 | concurrency, 25 | source, 26 | lichessdb, 27 | engine, 28 | enginedepth, 29 | enginemaxmoves, 30 | boardstyle, 31 | boardedges, 32 | ): 33 | self.networkstyle = networkstyle 34 | self.depth = depth 35 | self.source = source 36 | self.lichessdb = lichessdb 37 | self.engine = engine 38 | self.enginedepth = enginedepth 39 | self.enginemaxmoves = enginemaxmoves 40 | self.boardstyle = boardstyle 41 | self.boardedges = boardedges 42 | 43 | self.executorgraph = [ 44 | concurrent.futures.ThreadPoolExecutor(max_workers=concurrency) 45 | for i in range(0, depth + 1) 46 | ] 47 | self.executorwork = concurrent.futures.ThreadPoolExecutor( 48 | max_workers=concurrency 49 | ) 50 | self.visited = set() 51 | self.session = requests.Session() 52 | self.graph = graphviz.Digraph("ChessGraph", format="svg") 53 | self.cache = {} 54 | 55 | # We fix lichessbeta by giving the startpos a score of 0.35 56 | if self.source == "lichess": 57 | w, d, l, moves = self.lichess_api_call( 58 | "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq -" 59 | ) 60 | self.lichessbeta = (1 - 0.35) / math.log((w + d + l) / w - 1) 61 | else: 62 | self.lichessbeta = None 63 | 64 | def load_cache(self): 65 | try: 66 | with open("chessgraph.cache.pyc", "rb") as f: 67 | self.cache = pickle.load(f) 68 | except: 69 | self.cache = {} 70 | 71 | def store_cache(self): 72 | with open("chessgraph.cache.pyc", "wb") as f: 73 | pickle.dump(self.cache, f) 74 | 75 | def get_moves(self, epd): 76 | if self.source == "chessdb": 77 | return self.get_moves_chessdb(epd) 78 | elif self.source == "engine": 79 | return self.get_moves_engine(epd) 80 | elif self.source == "lichess": 81 | return self.get_moves_lichess(epd) 82 | else: 83 | assert False 84 | 85 | def get_bestscore_and_moves(self, board): 86 | if board.is_checkmate(): 87 | moves = [] 88 | bestscore = -30000 89 | elif ( 90 | board.is_stalemate() 91 | or board.is_insufficient_material() 92 | or board.can_claim_draw() 93 | ): 94 | moves = [] 95 | bestscore = 0 96 | else: 97 | moves = self.executorwork.submit(self.get_moves, board.epd()).result() 98 | if self.source != "chessdb": 99 | moves.sort(key=lambda item: item["score"], reverse=True) 100 | bestscore = int(moves[0]["score"]) if moves else None 101 | return bestscore, moves 102 | 103 | def get_moves_engine(self, epd): 104 | key = (epd, self.engine, self.enginedepth, self.enginemaxmoves) 105 | 106 | if key in self.cache: 107 | return self.cache[key] 108 | 109 | moves = [] 110 | engine = chess.engine.SimpleEngine.popen_uci(self.engine) 111 | board = chess.Board(epd) 112 | info = engine.analyse( 113 | board, 114 | chess.engine.Limit(depth=self.enginedepth), 115 | multipv=self.enginemaxmoves, 116 | info=chess.engine.INFO_SCORE | chess.engine.INFO_PV, 117 | ) 118 | engine.quit() 119 | for i in info: 120 | moves.append( 121 | { 122 | "score": i["score"].pov(board.turn).score(mate_score=30000), 123 | "uci": chess.Move.uci(i["pv"][0]), 124 | } 125 | ) 126 | 127 | self.cache[key] = moves 128 | 129 | return moves 130 | 131 | def get_moves_chessdb(self, epd): 132 | key = (epd, "chessdb") 133 | 134 | if key in self.cache: 135 | stdmoves = self.cache[key] 136 | if len(stdmoves) > 0: 137 | return stdmoves 138 | 139 | api = "http://www.chessdb.cn/cdb.php" 140 | url = api + "?action=queryall&board=" + parse.quote(epd) + "&json=1" 141 | timeout = 3 142 | 143 | moves = [] 144 | try: 145 | response = self.session.get(url, timeout=timeout) 146 | response.raise_for_status() 147 | data = response.json() 148 | if data["status"] == "ok": 149 | moves = data["moves"] 150 | elif data["status"] == "unknown": 151 | pass 152 | elif data["status"] == "rate limited exceeded": 153 | sys.stderr.write("rate") 154 | else: 155 | sys.stderr.write(data) 156 | except: 157 | pass 158 | 159 | stdmoves = [] 160 | for m in moves: 161 | stdmoves.append({"score": m["score"], "uci": m["uci"]}) 162 | 163 | self.cache[key] = stdmoves 164 | 165 | return stdmoves 166 | 167 | def lichess_wdl_to_score(self, w, d, l): 168 | total = w + d + l 169 | 170 | if w == l: 171 | return 0.0 172 | 173 | if w == total: 174 | return 10000 175 | 176 | if l == total: 177 | return -10000 178 | 179 | if w > l: 180 | return min( 181 | 10000, int(100 - 100 * self.lichessbeta * math.log(total / w - 1)) 182 | ) 183 | else: 184 | return max( 185 | -10000, -int(100 - 100 * self.lichessbeta * math.log(total / l - 1)) 186 | ) 187 | 188 | def lichess_api_call(self, epd): 189 | if self.lichessdb == "masters": 190 | specifics = "&topGames=0" 191 | else: 192 | specifics = ( 193 | "variant=standard" 194 | + "&speeds=blitz" 195 | + "&ratings=2000,2200,2500" 196 | + "&topGames=0&recentGames=0" 197 | ) 198 | 199 | url = ( 200 | "https://explorer.lichess.ovh/{}?".format(self.lichessdb) 201 | + specifics 202 | + "&moves={}".format(self.enginemaxmoves) 203 | + "&fen={}".format(parse.quote(epd)) 204 | ) 205 | 206 | timeout = 3 207 | 208 | try: 209 | response = self.session.get(url, timeout=timeout) 210 | response.raise_for_status() 211 | data = response.json() 212 | 213 | if epd.split()[1] == "w": 214 | w, d, l = int(data["white"]), int(data["draws"]), int(data["black"]) 215 | else: 216 | l, d, w = int(data["white"]), int(data["draws"]), int(data["black"]) 217 | moves = data["moves"] 218 | except: 219 | w = d = l = 0 220 | moves = [] 221 | 222 | return (w, d, l, moves) 223 | 224 | def get_moves_lichess(self, epd): 225 | key = (epd, "lichess", self.enginemaxmoves, self.lichessdb) 226 | 227 | if key in self.cache: 228 | stdmoves = self.cache[key] 229 | if len(stdmoves) > 0: 230 | return stdmoves 231 | 232 | w, d, l, moves = self.lichess_api_call(epd) 233 | 234 | stdmoves = [] 235 | for m in moves: 236 | if epd.split()[1] == "w": 237 | w, d, l = int(m["white"]), int(m["draws"]), int(m["black"]) 238 | else: 239 | l, d, w = int(m["white"]), int(m["draws"]), int(m["black"]) 240 | total = w + d + l 241 | # A parameter that ensures we have sufficient games to get a score 242 | lichessmingames = 10 243 | if total > lichessmingames: 244 | score = self.lichess_wdl_to_score(w, d, l) 245 | stdmoves.append({"score": score, "uci": m["uci"]}) 246 | 247 | self.cache[key] = stdmoves 248 | 249 | return stdmoves 250 | 251 | def node_name(self, board): 252 | if self.networkstyle == "graph": 253 | name = "graph - " + board.epd() 254 | elif self.networkstyle == "tree": 255 | movelist = [] 256 | while True: 257 | try: 258 | move = board.pop() 259 | movelist.append(move) 260 | except: 261 | break 262 | name = board.epd() + " moves " 263 | for move in reversed(movelist): 264 | board.push(move) 265 | name = name + " " + move.uci() 266 | else: 267 | raise () 268 | 269 | return name 270 | 271 | def write_node(self, board, score, showboard, pvNode, tooltip): 272 | epd = board.epd() 273 | nodename = self.node_name(board) 274 | 275 | color = "gold" if board.turn == chess.WHITE else "burlywood4" 276 | penwidth = "3" if pvNode else "1" 277 | 278 | epdweb = parse.quote(epd) 279 | URL = "https://www.chessdb.cn/queryc_en/?" + epdweb 280 | image = None 281 | 282 | if showboard and not self.boardstyle == "none": 283 | if self.boardstyle == "unicode": 284 | label = board.unicode(empty_square="\u00B7") 285 | elif self.boardstyle == "svg": 286 | filename = ( 287 | "node-" + hashlib.sha256(epd.encode("utf-8")).hexdigest() + ".svg" 288 | ) 289 | if not exists(filename): 290 | cairosvg.svg2svg( 291 | bytestring=chess.svg.board(board, size="200px").encode("utf-8"), 292 | write_to=filename, 293 | ) 294 | image = filename 295 | label = "" 296 | else: 297 | label = ( 298 | "None" 299 | if score is None 300 | else str(score if board.turn == chess.WHITE else -score) 301 | ) 302 | 303 | if image: 304 | self.graph.node( 305 | nodename, 306 | label=label, 307 | shape="box", 308 | color=color, 309 | penwidth=penwidth, 310 | URL=URL, 311 | image=image, 312 | tooltip=tooltip, 313 | ) 314 | else: 315 | self.graph.node( 316 | nodename, 317 | label=label, 318 | shape="box", 319 | color=color, 320 | penwidth=penwidth, 321 | fontname="Courier", 322 | URL=URL, 323 | tooltip=tooltip, 324 | ) 325 | 326 | def write_edge( 327 | self, nodefrom, nodeto, sanmove, ucimove, turn, score, pvEdge, lateEdge 328 | ): 329 | color = "gold" if turn == chess.WHITE else "burlywood4" 330 | penwidth = "3" if pvEdge else "1" 331 | fontname = "Helvetica-bold" if pvEdge else "Helvectica" 332 | style = "dashed" if lateEdge else "solid" 333 | labeltooltip = "{} ({}) : {}".format( 334 | sanmove, 335 | ucimove, 336 | "None" if score is None else str(score if turn == chess.WHITE else -score), 337 | ) 338 | tooltip = labeltooltip 339 | self.graph.edge( 340 | nodefrom, 341 | nodeto, 342 | label=sanmove, 343 | color=color, 344 | penwidth=penwidth, 345 | fontname=fontname, 346 | tooltip=tooltip, 347 | edgetooltip=tooltip, 348 | labeltooltip=labeltooltip, 349 | style=style, 350 | ) 351 | 352 | def recurse(self, board, depth, alpha, beta, pvNode, plyFromRoot): 353 | nodenamefrom = self.node_name(board) 354 | 355 | # terminate recursion if visited 356 | if nodenamefrom in self.visited: 357 | return 358 | else: 359 | self.visited.add(nodenamefrom) 360 | 361 | bestscore, moves = self.get_bestscore_and_moves(board) 362 | 363 | edgesfound = 0 364 | edgesdrawn = 0 365 | futures = [] 366 | turn = board.turn 367 | tooltip = board.epd() + " " 368 | 369 | # loop through the (sorted) moves that are within delta of the bestmove 370 | for m in moves: 371 | score = int(m["score"]) 372 | 373 | if score <= alpha: 374 | break 375 | 376 | ucimove = m["uci"] 377 | move = chess.Move.from_uci(ucimove) 378 | sanmove = board.san(move) 379 | board.push(move) 380 | nodenameto = self.node_name(board) 381 | edgesfound += 1 382 | pvEdge = pvNode and score == bestscore 383 | lateEdge = score != bestscore 384 | 385 | # no loops, otherwise recurse 386 | if score == bestscore: 387 | newDepth = depth - 1 388 | else: 389 | newDepth = depth - int(1.5 + math.log2(edgesfound)) 390 | 391 | if newDepth >= 0: 392 | if nodenameto not in self.visited: 393 | futures.append( 394 | self.executorgraph[depth].submit( 395 | self.recurse, 396 | board.copy(), 397 | newDepth, 398 | -beta, 399 | -alpha, 400 | pvEdge, 401 | plyFromRoot + 1, 402 | ) 403 | ) 404 | edgesdrawn += 1 405 | tooltip += "{} : {} ".format( 406 | sanmove, str(score if turn == chess.WHITE else -score) 407 | ) 408 | self.write_edge( 409 | nodenamefrom, 410 | nodenameto, 411 | sanmove, 412 | ucimove, 413 | turn, 414 | score, 415 | pvEdge, 416 | lateEdge, 417 | ) 418 | 419 | board.pop() 420 | 421 | concurrent.futures.wait(futures) 422 | 423 | remainingMoves = board.legal_moves.count() - edgesdrawn 424 | tooltip += "{} remaining {} ".format( 425 | remainingMoves, "move" if remainingMoves == 1 else "moves" 426 | ) 427 | 428 | if edgesdrawn == 0: 429 | tooltip += "terminal: {}".format( 430 | "None" 431 | if bestscore is None 432 | else str(bestscore if turn == chess.WHITE else -bestscore) 433 | ) 434 | 435 | self.write_node( 436 | board, 437 | bestscore, 438 | edgesdrawn >= self.boardedges 439 | or (pvNode and edgesdrawn == 0) 440 | or plyFromRoot == 0, 441 | pvNode, 442 | tooltip, 443 | ) 444 | 445 | def generate_graph(self, epd, alpha, beta, ralpha, rbeta, salpha, sbeta): 446 | # set initial board 447 | board = chess.Board(epd) 448 | 449 | score, _ = self.get_bestscore_and_moves(board) 450 | score = score if board.turn == chess.WHITE else -score 451 | 452 | if ralpha is not None: 453 | alpha = int(ralpha * score) 454 | elif salpha is not None: 455 | alpha = score - salpha 456 | 457 | if rbeta is not None: 458 | beta = int(rbeta * score) 459 | elif sbeta is not None: 460 | beta = score + sbeta 461 | 462 | print("root position epd : ", epd) 463 | print( 464 | f"alpha : {alpha}{' (alpha > eval!)' if alpha > score else ''}" 465 | ) 466 | print("eval : ", score) 467 | print( 468 | f"beta : {beta}{' (beta < eval!)' if beta < score else ''}" 469 | ) 470 | print("depth : ", self.depth) 471 | 472 | if board.turn == chess.WHITE: 473 | initialAlpha, initialBeta = alpha, beta 474 | else: 475 | initialAlpha, initialBeta = -beta, -alpha 476 | 477 | self.recurse( 478 | board, self.depth, initialAlpha, initialBeta, pvNode=True, plyFromRoot=0 479 | ) 480 | 481 | 482 | if __name__ == "__main__": 483 | parser = argparse.ArgumentParser( 484 | formatter_class=argparse.ArgumentDefaultsHelpFormatter, 485 | description="A utility to create a graph of moves from a specified chess position.", 486 | ) 487 | 488 | group = parser.add_mutually_exclusive_group() 489 | group.add_argument( 490 | "--position", 491 | type=str, 492 | default=chess.STARTING_FEN, 493 | help="FEN of the root position.", 494 | ) 495 | group.add_argument( 496 | "--san", 497 | help='Moves in SAN notation that lead to the root position. E.g. "1. g4".', 498 | ) 499 | 500 | groupa = parser.add_mutually_exclusive_group() 501 | groupa.add_argument( 502 | "--alpha", 503 | type=int, 504 | default=0, 505 | help="Lower bound on the score of variations to be followed (for white).", 506 | ) 507 | groupa.add_argument( 508 | "--ralpha", 509 | type=float, 510 | help="Set ALPHA = EVAL * RALPHA , where EVAL is the eval of the root position.", 511 | ) 512 | groupa.add_argument( 513 | "--salpha", 514 | type=int, 515 | help="Set ALPHA = EVAL - SALPHA.", 516 | ) 517 | 518 | groupb = parser.add_mutually_exclusive_group() 519 | groupb.add_argument( 520 | "--beta", 521 | type=int, 522 | default=15, 523 | help="Lower bound on the score of variations to be followed (for black).", 524 | ) 525 | groupb.add_argument( 526 | "--rbeta", 527 | type=float, 528 | help="Set BETA = EVAL * RBETA.", 529 | ) 530 | groupb.add_argument( 531 | "--sbeta", 532 | type=int, 533 | help="Set BETA = EVAL + SBETA.", 534 | ) 535 | 536 | parser.add_argument( 537 | "--depth", 538 | type=int, 539 | default=6, 540 | help="Maximum depth (in plies) of a followed variation.", 541 | ) 542 | 543 | parser.add_argument( 544 | "--concurrency", 545 | type=int, 546 | default=multiprocessing.cpu_count(), 547 | help="Number of cores to use for work / requests.", 548 | ) 549 | 550 | parser.add_argument( 551 | "--source", 552 | choices=["chessdb", "lichess", "engine"], 553 | type=str, 554 | default="chessdb", 555 | help="Use chessdb, lichess or an engine to score and rank moves.", 556 | ) 557 | 558 | parser.add_argument( 559 | "--lichessdb", 560 | choices=["masters", "lichess"], 561 | type=str, 562 | default="masters", 563 | help="Which lichess database to access: masters, or lichess players.", 564 | ) 565 | 566 | parser.add_argument( 567 | "--engine", 568 | type=str, 569 | default="stockfish.exe" 570 | if "windows" in platform.system().lower() 571 | else "stockfish", 572 | help="Name of the engine binary (with path as needed).", 573 | ) 574 | 575 | parser.add_argument( 576 | "--enginedepth", 577 | type=int, 578 | default=20, 579 | help="Depth of the search used by the engine in evaluation.", 580 | ) 581 | 582 | parser.add_argument( 583 | "--enginemaxmoves", 584 | type=int, 585 | default=10, 586 | help="Maximum number of moves (MultiPV) considered by the engine in evaluation.", 587 | ) 588 | 589 | parser.add_argument( 590 | "--networkstyle", 591 | choices=["graph", "tree"], 592 | type=str, 593 | default="graph", 594 | help="Selects the representation of the network as a graph (shows transpositions, compact) or a tree (simpler to follow, extended).", 595 | ) 596 | 597 | parser.add_argument( 598 | "--boardstyle", 599 | choices=["unicode", "svg", "none"], 600 | type=str, 601 | default="unicode", 602 | help="Which style to use to visualize a board.", 603 | ) 604 | 605 | parser.add_argument( 606 | "--boardedges", 607 | type=int, 608 | default=3, 609 | help="Minimum number of edges needed before a board is visualized in the node.", 610 | ) 611 | 612 | parser.add_argument( 613 | "--output", 614 | "-o", 615 | type=str, 616 | default="chess.svg", 617 | help="Name of the output file (image in .svg format).", 618 | ) 619 | 620 | parser.add_argument( 621 | "--embed", 622 | action=argparse.BooleanOptionalAction, 623 | default=False, 624 | help="If the individual svg boards should be embedded in the final .svg image. Unfortunately URLs are not preserved.", 625 | ) 626 | 627 | parser.add_argument( 628 | "--purgecache", 629 | action=argparse.BooleanOptionalAction, 630 | default=False, 631 | help="Do no use, and later overwrite, the cache file stored on disk (chessgraph.cache.pyc).", 632 | ) 633 | 634 | args = parser.parse_args() 635 | 636 | chessgraph = ChessGraph( 637 | networkstyle=args.networkstyle, 638 | depth=args.depth, 639 | concurrency=args.concurrency, 640 | source=args.source, 641 | lichessdb=args.lichessdb, 642 | engine=args.engine, 643 | enginedepth=args.enginedepth, 644 | enginemaxmoves=args.enginemaxmoves, 645 | boardstyle=args.boardstyle, 646 | boardedges=args.boardedges, 647 | ) 648 | 649 | # load previously computed nodes in a cache 650 | if not args.purgecache: 651 | chessgraph.load_cache() 652 | 653 | if args.san is not None: 654 | import chess.pgn, io 655 | 656 | if args.san: 657 | pgn = io.StringIO(args.san) 658 | fen = chess.pgn.read_game(pgn).end().board().fen() 659 | else: 660 | fen = chess.STARTING_FEN # passing empty string to --san gives startpos 661 | else: 662 | fen = args.position 663 | 664 | # generate the content of the dotfile 665 | chessgraph.generate_graph( 666 | fen, args.alpha, args.beta, args.ralpha, args.rbeta, args.salpha, args.sbeta 667 | ) 668 | 669 | # store updated cache 670 | chessgraph.store_cache() 671 | 672 | # generate the svg image (calls graphviz under the hood) 673 | svgpiped = chessgraph.graph.pipe() 674 | 675 | if args.embed: 676 | # this embeds the images of the boards generated. 677 | # Unfortunately, does remove the URLs that link to chessdb. 678 | # probably some smarter manipulation directly on the xml 679 | # would also allow to shrink the image size (each board embeds pieces etc.) 680 | cairosvg.svg2svg( 681 | bytestring=svgpiped, 682 | write_to=args.output, 683 | ) 684 | else: 685 | with open(args.output, "w", encoding="utf-8") as f: 686 | f.write(svgpiped.decode("utf-8")) 687 | -------------------------------------------------------------------------------- /spanish.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | ChessGraph 11 | 12 | 13 | 14 | r1bqkbnr/pppp1ppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R b KQkq - 15 | 16 | 17 | ♜ · ♝ ♛ ♚ ♝ ♞ ♜ 18 | ♟ ♟ ♟ ♟ · ♟ ♟ ♟ 19 | · · ♞ · · · · · 20 | · ♗ · · ♟ · · · 21 | · · · · ♙ · · · 22 | · · · · · ♘ · · 23 | ♙ ♙ ♙ ♙ · ♙ ♙ ♙ 24 | ♖ ♘ ♗ ♕ ♔ · · ♖ 25 | 26 | 27 | 28 | 29 | 30 | r1bqkb1r/pppp1ppp/2n2n2/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq - 31 | 32 | 33 | 31 34 | 35 | 36 | 37 | 38 | 39 | r1bqkbnr/pppp1ppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R b KQkq -->r1bqkb1r/pppp1ppp/2n2n2/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq - 40 | 41 | 42 | 43 | 44 | 45 | 46 | Nf6 47 | 48 | 49 | 50 | 51 | 52 | r1bqkbnr/1ppp1ppp/p1n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq - 53 | 54 | 55 | 42 56 | 57 | 58 | 59 | 60 | 61 | r1bqkbnr/pppp1ppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R b KQkq -->r1bqkbnr/1ppp1ppp/p1n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq - 62 | 63 | 64 | 65 | 66 | 67 | 68 | a6 69 | 70 | 71 | 72 | 73 | 74 | r1bqkbnr/pppp1ppp/8/1B2p3/3nP3/5N2/PPPP1PPP/RNBQK2R w KQkq - 75 | 76 | 77 | 57 78 | 79 | 80 | 81 | 82 | 83 | r1bqkbnr/pppp1ppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R b KQkq -->r1bqkbnr/pppp1ppp/8/1B2p3/3nP3/5N2/PPPP1PPP/RNBQK2R w KQkq - 84 | 85 | 86 | 87 | 88 | 89 | 90 | Nd4 91 | 92 | 93 | 94 | 95 | 96 | r1bqkbnr/pppp2pp/2n5/1B2pp2/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq - 97 | 98 | 99 | ♜ · ♝ ♛ ♚ ♝ ♞ ♜ 100 | ♟ ♟ ♟ ♟ · · ♟ ♟ 101 | · · ♞ · · · · · 102 | · ♗ · · ♟ ♟ · · 103 | · · · · ♙ · · · 104 | · · · · · ♘ · · 105 | ♙ ♙ ♙ ♙ · ♙ ♙ ♙ 106 | ♖ ♘ ♗ ♕ ♔ · · ♖ 107 | 108 | 109 | 110 | 111 | 112 | r1bqkbnr/pppp1ppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R b KQkq -->r1bqkbnr/pppp2pp/2n5/1B2pp2/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq - 113 | 114 | 115 | 116 | 117 | 118 | 119 | f5 120 | 121 | 122 | 123 | 124 | 125 | r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq - 126 | 127 | 128 | ♜ · ♝ ♛ ♚ · ♞ ♜ 129 | ♟ ♟ ♟ ♟ ♝ ♟ ♟ ♟ 130 | · · ♞ · · · · · 131 | · ♗ · · ♟ · · · 132 | · · · · ♙ · · · 133 | · · · · · ♘ · · 134 | ♙ ♙ ♙ ♙ · ♙ ♙ ♙ 135 | ♖ ♘ ♗ ♕ ♔ · · ♖ 136 | 137 | 138 | 139 | 140 | 141 | r1bqkbnr/pppp1ppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R b KQkq -->r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq - 142 | 143 | 144 | 145 | 146 | 147 | 148 | Be7 149 | 150 | 151 | 152 | 153 | 154 | r1bqkb1r/pppp1ppp/2n2n2/1B2p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 b kq - 155 | 156 | 157 | 24 158 | 159 | 160 | 161 | 162 | 163 | r1bqkb1r/pppp1ppp/2n2n2/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq -->r1bqkb1r/pppp1ppp/2n2n2/1B2p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 b kq - 164 | 165 | 166 | 167 | 168 | 169 | 170 | O-O 171 | 172 | 173 | 174 | 175 | 176 | r1bqkbnr/1ppp1ppp/p1n5/4p3/B3P3/5N2/PPPP1PPP/RNBQK2R b KQkq - 177 | 178 | 179 | 49 180 | 181 | 182 | 183 | 184 | 185 | r1bqkbnr/1ppp1ppp/p1n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq -->r1bqkbnr/1ppp1ppp/p1n5/4p3/B3P3/5N2/PPPP1PPP/RNBQK2R b KQkq - 186 | 187 | 188 | 189 | 190 | 191 | 192 | Ba4 193 | 194 | 195 | 196 | 197 | 198 | r1bqkbnr/pppp1ppp/8/1B2p3/3NP3/8/PPPP1PPP/RNBQK2R b KQkq - 199 | 200 | 201 | 59 202 | 203 | 204 | 205 | 206 | 207 | r1bqkbnr/pppp1ppp/8/1B2p3/3nP3/5N2/PPPP1PPP/RNBQK2R w KQkq -->r1bqkbnr/pppp1ppp/8/1B2p3/3NP3/8/PPPP1PPP/RNBQK2R b KQkq - 208 | 209 | 210 | 211 | 212 | 213 | 214 | Nxd4 215 | 216 | 217 | 218 | 219 | 220 | r1bqkbnr/pppp1ppp/8/4p3/2BnP3/5N2/PPPP1PPP/RNBQK2R b KQkq - 221 | 222 | 223 | 44 224 | 225 | 226 | 227 | 228 | 229 | r1bqkbnr/pppp1ppp/8/1B2p3/3nP3/5N2/PPPP1PPP/RNBQK2R w KQkq -->r1bqkbnr/pppp1ppp/8/4p3/2BnP3/5N2/PPPP1PPP/RNBQK2R b KQkq - 230 | 231 | 232 | 233 | 234 | 235 | 236 | Bc4 237 | 238 | 239 | 240 | 241 | 242 | r1bqkbnr/pppp2pp/2n5/1B2pp2/4P3/2N2N2/PPPP1PPP/R1BQK2R b KQkq - 243 | 244 | 245 | 68 246 | 247 | 248 | 249 | 250 | 251 | r1bqkbnr/pppp2pp/2n5/1B2pp2/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq -->r1bqkbnr/pppp2pp/2n5/1B2pp2/4P3/2N2N2/PPPP1PPP/R1BQK2R b KQkq - 252 | 253 | 254 | 255 | 256 | 257 | 258 | Nc3 259 | 260 | 261 | 262 | 263 | 264 | r1bqkbnr/pppp2pp/2n5/1B2pp2/4P3/3P1N2/PPP2PPP/RNBQK2R b KQkq - 265 | 266 | 267 | 44 268 | 269 | 270 | 271 | 272 | 273 | r1bqkbnr/pppp2pp/2n5/1B2pp2/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq -->r1bqkbnr/pppp2pp/2n5/1B2pp2/4P3/3P1N2/PPP2PPP/RNBQK2R b KQkq - 274 | 275 | 276 | 277 | 278 | 279 | 280 | d3 281 | 282 | 283 | 284 | 285 | 286 | r1bqkbnr/pppp2pp/2n5/1B2pp2/3PP3/5N2/PPP2PPP/RNBQK2R b KQkq - 287 | 288 | 289 | 15 290 | 291 | 292 | 293 | 294 | 295 | r1bqkbnr/pppp2pp/2n5/1B2pp2/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq -->r1bqkbnr/pppp2pp/2n5/1B2pp2/3PP3/5N2/PPP2PPP/RNBQK2R b KQkq - 296 | 297 | 298 | 299 | 300 | 301 | 302 | d4 303 | 304 | 305 | 306 | 307 | 308 | r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 b kq - 309 | 310 | 311 | 48 312 | 313 | 314 | 315 | 316 | 317 | r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq -->r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 b kq - 318 | 319 | 320 | 321 | 322 | 323 | 324 | O-O 325 | 326 | 327 | 328 | 329 | 330 | r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/3P1N2/PPP2PPP/RNBQK2R b KQkq - 331 | 332 | 333 | 31 334 | 335 | 336 | 337 | 338 | 339 | r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq -->r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/3P1N2/PPP2PPP/RNBQK2R b KQkq - 340 | 341 | 342 | 343 | 344 | 345 | 346 | d3 347 | 348 | 349 | 350 | 351 | 352 | r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/2N2N2/PPPP1PPP/R1BQK2R b KQkq - 353 | 354 | 355 | 37 356 | 357 | 358 | 359 | 360 | 361 | r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq -->r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/2N2N2/PPPP1PPP/R1BQK2R b KQkq - 362 | 363 | 364 | 365 | 366 | 367 | 368 | Nc3 369 | 370 | 371 | 372 | 373 | 374 | r1bqk1nr/ppppbppp/2n5/4p3/B3P3/5N2/PPPP1PPP/RNBQK2R b KQkq - 375 | 376 | 377 | 26 378 | 379 | 380 | 381 | 382 | 383 | r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq -->r1bqk1nr/ppppbppp/2n5/4p3/B3P3/5N2/PPPP1PPP/RNBQK2R b KQkq - 384 | 385 | 386 | 387 | 388 | 389 | 390 | Ba4 391 | 392 | 393 | 394 | 395 | 396 | r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/2P2N2/PP1P1PPP/RNBQK2R b KQkq - 397 | 398 | 399 | 15 400 | 401 | 402 | 403 | 404 | 405 | r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq -->r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/2P2N2/PP1P1PPP/RNBQK2R b KQkq - 406 | 407 | 408 | 409 | 410 | 411 | 412 | c3 413 | 414 | 415 | 416 | 417 | 418 | r1bqk1nr/ppppbppp/2n5/1B2p3/3PP3/5N2/PPP2PPP/RNBQK2R b KQkq - 419 | 420 | 421 | 26 422 | 423 | 424 | 425 | 426 | 427 | r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq -->r1bqk1nr/ppppbppp/2n5/1B2p3/3PP3/5N2/PPP2PPP/RNBQK2R b KQkq - 428 | 429 | 430 | 431 | 432 | 433 | 434 | d4 435 | 436 | 437 | 438 | 439 | 440 | r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/5N2/PPPPQPPP/RNB1K2R b KQkq - 441 | 442 | 443 | 30 444 | 445 | 446 | 447 | 448 | 449 | r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq -->r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/5N2/PPPPQPPP/RNB1K2R b KQkq - 450 | 451 | 452 | 453 | 454 | 455 | 456 | Qe2 457 | 458 | 459 | 460 | 461 | 462 | r1bqkbnr/pppp2pp/2n5/1B2p3/4p3/3P1N2/PPP2PPP/RNBQK2R w KQkq - 463 | 464 | 465 | 64 466 | 467 | 468 | 469 | 470 | 471 | r1bqkbnr/pppp2pp/2n5/1B2pp2/4P3/3P1N2/PPP2PPP/RNBQK2R b KQkq -->r1bqkbnr/pppp2pp/2n5/1B2p3/4p3/3P1N2/PPP2PPP/RNBQK2R w KQkq - 472 | 473 | 474 | 475 | 476 | 477 | 478 | fxe4 479 | 480 | 481 | 482 | 483 | 484 | r1bqkbnr/pppp2pp/2n5/1B2p3/3Pp3/5N2/PPP2PPP/RNBQK2R w KQkq - 485 | 486 | 487 | 8 488 | 489 | 490 | 491 | 492 | 493 | r1bqkbnr/pppp2pp/2n5/1B2pp2/3PP3/5N2/PPP2PPP/RNBQK2R b KQkq -->r1bqkbnr/pppp2pp/2n5/1B2p3/3Pp3/5N2/PPP2PPP/RNBQK2R w KQkq - 494 | 495 | 496 | 497 | 498 | 499 | 500 | fxe4 501 | 502 | 503 | 504 | 505 | 506 | r1bqkbnr/2pp1ppp/p1n5/1p2p3/B3P3/5N2/PPPP1PPP/RNBQK2R w KQkq - 507 | 508 | 509 | 50 510 | 511 | 512 | 513 | 514 | 515 | r1bqkbnr/1ppp1ppp/p1n5/4p3/B3P3/5N2/PPPP1PPP/RNBQK2R b KQkq -->r1bqkbnr/2pp1ppp/p1n5/1p2p3/B3P3/5N2/PPPP1PPP/RNBQK2R w KQkq - 516 | 517 | 518 | 519 | 520 | 521 | 522 | b5 523 | 524 | 525 | 526 | 527 | 528 | r1bqkb1r/pppp1ppp/2n5/1B2p3/4n3/5N2/PPPP1PPP/RNBQ1RK1 w kq - 529 | 530 | 531 | 37 532 | 533 | 534 | 535 | 536 | 537 | r1bqkb1r/pppp1ppp/2n2n2/1B2p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 b kq -->r1bqkb1r/pppp1ppp/2n5/1B2p3/4n3/5N2/PPPP1PPP/RNBQ1RK1 w kq - 538 | 539 | 540 | 541 | 542 | 543 | 544 | Nxe4 545 | 546 | 547 | 548 | 549 | 550 | r1bqk2r/pppp1ppp/2n2n2/1Bb1p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 w kq - 551 | 552 | 553 | ♜ · ♝ ♛ ♚ · · ♜ 554 | ♟ ♟ ♟ ♟ · ♟ ♟ ♟ 555 | · · ♞ · · ♞ · · 556 | · ♗ ♝ · ♟ · · · 557 | · · · · ♙ · · · 558 | · · · · · ♘ · · 559 | ♙ ♙ ♙ ♙ · ♙ ♙ ♙ 560 | ♖ ♘ ♗ ♕ · ♖ ♔ · 561 | 562 | 563 | 564 | 565 | 566 | r1bqkb1r/pppp1ppp/2n2n2/1B2p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 b kq -->r1bqk2r/pppp1ppp/2n2n2/1Bb1p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 w kq - 567 | 568 | 569 | 570 | 571 | 572 | 573 | Bc5 574 | 575 | 576 | 577 | 578 | 579 | r1bqkbnr/pppp1ppp/8/4p3/2B1P3/5n2/PPPP1PPP/RNBQK2R w KQkq - 580 | 581 | 582 | 33 583 | 584 | 585 | 586 | 587 | 588 | r1bqkbnr/pppp1ppp/8/4p3/2BnP3/5N2/PPPP1PPP/RNBQK2R b KQkq -->r1bqkbnr/pppp1ppp/8/4p3/2B1P3/5n2/PPPP1PPP/RNBQK2R w KQkq - 589 | 590 | 591 | 592 | 593 | 594 | 595 | Nxf3+ 596 | 597 | 598 | 599 | 600 | 601 | r1bqk1nr/1pppbppp/p1n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 w kq - 602 | 603 | 604 | 73 605 | 606 | 607 | 608 | 609 | 610 | r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 b kq -->r1bqk1nr/1pppbppp/p1n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 w kq - 611 | 612 | 613 | 614 | 615 | 616 | 617 | a6 618 | 619 | 620 | 621 | 622 | 623 | r1bqk1nr/ppp1bppp/2np4/1B2p3/4P3/3P1N2/PPP2PPP/RNBQK2R w KQkq - 624 | 625 | 626 | 31 627 | 628 | 629 | 630 | 631 | 632 | r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/3P1N2/PPP2PPP/RNBQK2R b KQkq -->r1bqk1nr/ppp1bppp/2np4/1B2p3/4P3/3P1N2/PPP2PPP/RNBQK2R w KQkq - 633 | 634 | 635 | 636 | 637 | 638 | 639 | d6 640 | 641 | 642 | 643 | 644 | 645 | r1bqk1nr/pppp1ppp/2n2b2/1B2p3/4P3/3P1N2/PPP2PPP/RNBQK2R w KQkq - 646 | 647 | 648 | 50 649 | 650 | 651 | 652 | 653 | 654 | r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/3P1N2/PPP2PPP/RNBQK2R b KQkq -->r1bqk1nr/pppp1ppp/2n2b2/1B2p3/4P3/3P1N2/PPP2PPP/RNBQK2R w KQkq - 655 | 656 | 657 | 658 | 659 | 660 | 661 | Bf6 662 | 663 | 664 | 665 | 666 | 667 | r1bqk2r/ppppbppp/2n2n2/1B2p3/4P3/2N2N2/PPPP1PPP/R1BQK2R w KQkq - 668 | 669 | 670 | 41 671 | 672 | 673 | 674 | 675 | 676 | r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/2N2N2/PPPP1PPP/R1BQK2R b KQkq -->r1bqk2r/ppppbppp/2n2n2/1B2p3/4P3/2N2N2/PPPP1PPP/R1BQK2R w KQkq - 677 | 678 | 679 | 680 | 681 | 682 | 683 | Nf6 684 | 685 | 686 | 687 | 688 | 689 | r1bqk1nr/ppppb1pp/2n5/4pp2/B3P3/5N2/PPPP1PPP/RNBQK2R w KQkq - 690 | 691 | 692 | 33 693 | 694 | 695 | 696 | 697 | 698 | r1bqk1nr/ppppbppp/2n5/4p3/B3P3/5N2/PPPP1PPP/RNBQK2R b KQkq -->r1bqk1nr/ppppb1pp/2n5/4pp2/B3P3/5N2/PPPP1PPP/RNBQK2R w KQkq - 699 | 700 | 701 | 702 | 703 | 704 | 705 | f5 706 | 707 | 708 | 709 | 710 | 711 | r1bqk1nr/ppp1bppp/2np4/4p3/B3P3/5N2/PPPP1PPP/RNBQK2R w KQkq - 712 | 713 | 714 | 46 715 | 716 | 717 | 718 | 719 | 720 | r1bqk1nr/ppppbppp/2n5/4p3/B3P3/5N2/PPPP1PPP/RNBQK2R b KQkq -->r1bqk1nr/ppp1bppp/2np4/4p3/B3P3/5N2/PPPP1PPP/RNBQK2R w KQkq - 721 | 722 | 723 | 724 | 725 | 726 | 727 | d6 728 | 729 | 730 | 731 | 732 | 733 | r1bqk1nr/ppppb1pp/2n5/1B2pp2/4P3/2P2N2/PP1P1PPP/RNBQK2R w KQkq - 734 | 735 | 736 | 28 737 | 738 | 739 | 740 | 741 | 742 | r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/2P2N2/PP1P1PPP/RNBQK2R b KQkq -->r1bqk1nr/ppppb1pp/2n5/1B2pp2/4P3/2P2N2/PP1P1PPP/RNBQK2R w KQkq - 743 | 744 | 745 | 746 | 747 | 748 | 749 | f5 750 | 751 | 752 | 753 | 754 | 755 | r1bqk2r/ppppbppp/2n2n2/1B2p3/4P3/2P2N2/PP1P1PPP/RNBQK2R w KQkq - 756 | 757 | 758 | 48 759 | 760 | 761 | 762 | 763 | 764 | r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/2P2N2/PP1P1PPP/RNBQK2R b KQkq -->r1bqk2r/ppppbppp/2n2n2/1B2p3/4P3/2P2N2/PP1P1PPP/RNBQK2R w KQkq - 765 | 766 | 767 | 768 | 769 | 770 | 771 | Nf6 772 | 773 | 774 | 775 | 776 | 777 | r1bqk1nr/ppppbppp/2n5/1B6/3pP3/5N2/PPP2PPP/RNBQK2R w KQkq - 778 | 779 | 780 | 30 781 | 782 | 783 | 784 | 785 | 786 | r1bqk1nr/ppppbppp/2n5/1B2p3/3PP3/5N2/PPP2PPP/RNBQK2R b KQkq -->r1bqk1nr/ppppbppp/2n5/1B6/3pP3/5N2/PPP2PPP/RNBQK2R w KQkq - 787 | 788 | 789 | 790 | 791 | 792 | 793 | exd4 794 | 795 | 796 | 797 | 798 | 799 | r1bqk2r/ppppbppp/2n2n2/1B2p3/4P3/5N2/PPPPQPPP/RNB1K2R w KQkq - 800 | 801 | 802 | 30 803 | 804 | 805 | 806 | 807 | 808 | r1bqk1nr/ppppbppp/2n5/1B2p3/4P3/5N2/PPPPQPPP/RNB1K2R b KQkq -->r1bqk2r/ppppbppp/2n2n2/1B2p3/4P3/5N2/PPPPQPPP/RNB1K2R w KQkq - 809 | 810 | 811 | 812 | 813 | 814 | 815 | Nf6 816 | 817 | 818 | 819 | 820 | 821 | r1bqkbnr/2pp1ppp/p1n5/1p2p3/4P3/1B3N2/PPPP1PPP/RNBQK2R b KQkq - 822 | 823 | 824 | 50 825 | 826 | 827 | 828 | 829 | 830 | r1bqkbnr/2pp1ppp/p1n5/1p2p3/B3P3/5N2/PPPP1PPP/RNBQK2R w KQkq -->r1bqkbnr/2pp1ppp/p1n5/1p2p3/4P3/1B3N2/PPPP1PPP/RNBQK2R b KQkq - 831 | 832 | 833 | 834 | 835 | 836 | 837 | Bb3 838 | 839 | 840 | 841 | 842 | 843 | r1bqk1nr/ppppb1pp/2n5/4pp2/B3P3/3P1N2/PPP2PPP/RNBQK2R b KQkq - 844 | 845 | 846 | 19 847 | 848 | 849 | 850 | 851 | 852 | r1bqk1nr/ppppb1pp/2n5/4pp2/B3P3/5N2/PPPP1PPP/RNBQK2R w KQkq -->r1bqk1nr/ppppb1pp/2n5/4pp2/B3P3/3P1N2/PPP2PPP/RNBQK2R b KQkq - 853 | 854 | 855 | 856 | 857 | 858 | 859 | d3 860 | 861 | 862 | 863 | 864 | 865 | r1bqk1nr/ppp1bppp/2np4/1B2p3/4P3/3P1N2/PPP2PPP/RNBQ1RK1 b kq - 866 | 867 | 868 | 11 869 | 870 | 871 | 872 | 873 | 874 | r1bqk1nr/ppp1bppp/2np4/1B2p3/4P3/3P1N2/PPP2PPP/RNBQK2R w KQkq -->r1bqk1nr/ppp1bppp/2np4/1B2p3/4P3/3P1N2/PPP2PPP/RNBQ1RK1 b kq - 875 | 876 | 877 | 878 | 879 | 880 | 881 | O-O 882 | 883 | 884 | 885 | 886 | 887 | r1bqk1nr/pppp1ppp/2n2b2/1B2p3/4P3/2PP1N2/PP3PPP/RNBQK2R b KQkq - 888 | 889 | 890 | 47 891 | 892 | 893 | 894 | 895 | 896 | r1bqk1nr/pppp1ppp/2n2b2/1B2p3/4P3/3P1N2/PPP2PPP/RNBQK2R w KQkq -->r1bqk1nr/pppp1ppp/2n2b2/1B2p3/4P3/2PP1N2/PP3PPP/RNBQK2R b KQkq - 897 | 898 | 899 | 900 | 901 | 902 | 903 | c3 904 | 905 | 906 | 907 | 908 | 909 | r1bqkbnr/pppp1ppp/8/4p3/2B1P3/5Q2/PPPP1PPP/RNB1K2R b KQkq - 910 | 911 | 912 | 22 913 | 914 | 915 | 916 | 917 | 918 | r1bqkbnr/pppp1ppp/8/4p3/2B1P3/5n2/PPPP1PPP/RNBQK2R w KQkq -->r1bqkbnr/pppp1ppp/8/4p3/2B1P3/5Q2/PPPP1PPP/RNB1K2R b KQkq - 919 | 920 | 921 | 922 | 923 | 924 | 925 | Qxf3 926 | 927 | 928 | 929 | 930 | 931 | r1bqkb1r/pppp1ppp/2n5/1B2p3/4n3/5N2/PPPP1PPP/RNBQR1K1 b kq - 932 | 933 | 934 | 31 935 | 936 | 937 | 938 | 939 | 940 | r1bqkb1r/pppp1ppp/2n5/1B2p3/4n3/5N2/PPPP1PPP/RNBQ1RK1 w kq -->r1bqkb1r/pppp1ppp/2n5/1B2p3/4n3/5N2/PPPP1PPP/RNBQR1K1 b kq - 941 | 942 | 943 | 944 | 945 | 946 | 947 | Re1 948 | 949 | 950 | 951 | 952 | 953 | r1bqk2r/pppp1ppp/2n2n2/1Bb1N3/4P3/8/PPPP1PPP/RNBQ1RK1 b kq - 954 | 955 | 956 | 51 957 | 958 | 959 | 960 | 961 | 962 | r1bqk2r/pppp1ppp/2n2n2/1Bb1p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 w kq -->r1bqk2r/pppp1ppp/2n2n2/1Bb1N3/4P3/8/PPPP1PPP/RNBQ1RK1 b kq - 963 | 964 | 965 | 966 | 967 | 968 | 969 | Nxe5 970 | 971 | 972 | 973 | 974 | 975 | r1bqk2r/pppp1ppp/2n2n2/1Bb1p3/4P3/2P2N2/PP1P1PPP/RNBQ1RK1 b kq - 976 | 977 | 978 | 38 979 | 980 | 981 | 982 | 983 | 984 | r1bqk2r/pppp1ppp/2n2n2/1Bb1p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 w kq -->r1bqk2r/pppp1ppp/2n2n2/1Bb1p3/4P3/2P2N2/PP1P1PPP/RNBQ1RK1 b kq - 985 | 986 | 987 | 988 | 989 | 990 | 991 | c3 992 | 993 | 994 | 995 | 996 | 997 | r1bqk2r/pppp1ppp/2n2n2/1Bb1p3/4P3/2N2N2/PPPP1PPP/R1BQ1RK1 b kq - 998 | 999 | 1000 | 7 1001 | 1002 | 1003 | 1004 | 1005 | 1006 | r1bqk2r/pppp1ppp/2n2n2/1Bb1p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 w kq -->r1bqk2r/pppp1ppp/2n2n2/1Bb1p3/4P3/2N2N2/PPPP1PPP/R1BQ1RK1 b kq - 1007 | 1008 | 1009 | 1010 | 1011 | 1012 | 1013 | Nc3 1014 | 1015 | 1016 | 1017 | 1018 | 1019 | r1bqk1nr/1pppbppp/p1B5/4p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 b kq - 1020 | 1021 | 1022 | 49 1023 | 1024 | 1025 | 1026 | 1027 | 1028 | r1bqk1nr/1pppbppp/p1n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 w kq -->r1bqk1nr/1pppbppp/p1B5/4p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 b kq - 1029 | 1030 | 1031 | 1032 | 1033 | 1034 | 1035 | Bxc6 1036 | 1037 | 1038 | 1039 | 1040 | 1041 | r1bqk1nr/1pppbppp/p1n5/4p3/B3P3/5N2/PPPP1PPP/RNBQ1RK1 b kq - 1042 | 1043 | 1044 | 42 1045 | 1046 | 1047 | 1048 | 1049 | 1050 | r1bqk1nr/1pppbppp/p1n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 w kq -->r1bqk1nr/1pppbppp/p1n5/4p3/B3P3/5N2/PPPP1PPP/RNBQ1RK1 b kq - 1051 | 1052 | 1053 | 1054 | 1055 | 1056 | 1057 | Ba4 1058 | 1059 | 1060 | 1061 | 1062 | 1063 | r1bqkbnr/pppp2pp/2n5/1B2p3/4P3/5N2/PPP2PPP/RNBQK2R b KQkq - 1064 | 1065 | 1066 | 49 1067 | 1068 | 1069 | 1070 | 1071 | 1072 | r1bqkbnr/pppp2pp/2n5/1B2p3/4p3/3P1N2/PPP2PPP/RNBQK2R w KQkq -->r1bqkbnr/pppp2pp/2n5/1B2p3/4P3/5N2/PPP2PPP/RNBQK2R b KQkq - 1073 | 1074 | 1075 | 1076 | 1077 | 1078 | 1079 | dxe4 1080 | 1081 | 1082 | 1083 | 1084 | 1085 | r1bqk2r/ppppbppp/2n2n2/1B2p3/4P3/2N2N2/PPPP1PPP/R1BQ1RK1 b kq - 1086 | 1087 | 1088 | 43 1089 | 1090 | 1091 | 1092 | 1093 | 1094 | r1bqk2r/ppppbppp/2n2n2/1B2p3/4P3/2N2N2/PPPP1PPP/R1BQK2R w KQkq -->r1bqk2r/ppppbppp/2n2n2/1B2p3/4P3/2N2N2/PPPP1PPP/R1BQ1RK1 b kq - 1095 | 1096 | 1097 | 1098 | 1099 | 1100 | 1101 | O-O 1102 | 1103 | 1104 | 1105 | 1106 | 1107 | r1bqkb1r/pppp1ppp/5n2/4p3/2B1P3/5Q2/PPPP1PPP/RNB1K2R w KQkq - 1108 | 1109 | 1110 | 31 1111 | 1112 | 1113 | 1114 | 1115 | 1116 | r1bqkbnr/pppp1ppp/8/4p3/2B1P3/5Q2/PPPP1PPP/RNB1K2R b KQkq -->r1bqkb1r/pppp1ppp/5n2/4p3/2B1P3/5Q2/PPPP1PPP/RNB1K2R w KQkq - 1117 | 1118 | 1119 | 1120 | 1121 | 1122 | 1123 | Nf6 1124 | 1125 | 1126 | 1127 | 1128 | 1129 | r1bqkb1r/pppp1ppp/2nn4/1B2p3/8/5N2/PPPP1PPP/RNBQR1K1 w kq - 1130 | 1131 | 1132 | 32 1133 | 1134 | 1135 | 1136 | 1137 | 1138 | r1bqkb1r/pppp1ppp/2n5/1B2p3/4n3/5N2/PPPP1PPP/RNBQR1K1 b kq -->r1bqkb1r/pppp1ppp/2nn4/1B2p3/8/5N2/PPPP1PPP/RNBQR1K1 w kq - 1139 | 1140 | 1141 | 1142 | 1143 | 1144 | 1145 | Nd6 1146 | 1147 | 1148 | 1149 | 1150 | 1151 | r1bqk1nr/1pp1bppp/p1p5/4p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 w kq - 1152 | 1153 | 1154 | 37 1155 | 1156 | 1157 | 1158 | 1159 | 1160 | r1bqk1nr/1pppbppp/p1B5/4p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 b kq -->r1bqk1nr/1pp1bppp/p1p5/4p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 w kq - 1161 | 1162 | 1163 | 1164 | 1165 | 1166 | 1167 | dxc6 1168 | 1169 | 1170 | 1171 | 1172 | 1173 | r1bqk2r/1pppbppp/p1n2n2/4p3/B3P3/5N2/PPPP1PPP/RNBQ1RK1 w kq - 1174 | 1175 | 1176 | 51 1177 | 1178 | 1179 | 1180 | 1181 | 1182 | r1bqk1nr/1pppbppp/p1n5/4p3/B3P3/5N2/PPPP1PPP/RNBQ1RK1 b kq -->r1bqk2r/1pppbppp/p1n2n2/4p3/B3P3/5N2/PPPP1PPP/RNBQ1RK1 w kq - 1183 | 1184 | 1185 | 1186 | 1187 | 1188 | 1189 | Nf6 1190 | 1191 | 1192 | 1193 | 1194 | 1195 | r1bqk1nr/1pp1bppp/p1np4/1B2p3/4P3/3P1N2/PPP2PPP/RNBQ1RK1 w kq - 1196 | 1197 | 1198 | 20 1199 | 1200 | 1201 | 1202 | 1203 | 1204 | r1bqk1nr/ppp1bppp/2np4/1B2p3/4P3/3P1N2/PPP2PPP/RNBQ1RK1 b kq -->r1bqk1nr/1pp1bppp/p1np4/1B2p3/4P3/3P1N2/PPP2PPP/RNBQ1RK1 w kq - 1205 | 1206 | 1207 | 1208 | 1209 | 1210 | 1211 | a6 1212 | 1213 | 1214 | 1215 | 1216 | 1217 | r1bqkb1r/pppp2pp/2n2n2/1B2p3/4P3/5N2/PPP2PPP/RNBQK2R w KQkq - 1218 | 1219 | 1220 | 49 1221 | 1222 | 1223 | 1224 | 1225 | 1226 | r1bqkbnr/pppp2pp/2n5/1B2p3/4P3/5N2/PPP2PPP/RNBQK2R b KQkq -->r1bqkb1r/pppp2pp/2n2n2/1B2p3/4P3/5N2/PPP2PPP/RNBQK2R w KQkq - 1227 | 1228 | 1229 | 1230 | 1231 | 1232 | 1233 | Nf6 1234 | 1235 | 1236 | 1237 | 1238 | 1239 | r1bq1rk1/pppp1ppp/2n2n2/1Bb1p3/4P3/2P2N2/PP1P1PPP/RNBQ1RK1 w - - 1240 | 1241 | 1242 | 47 1243 | 1244 | 1245 | 1246 | 1247 | 1248 | r1bqk2r/pppp1ppp/2n2n2/1Bb1p3/4P3/2P2N2/PP1P1PPP/RNBQ1RK1 b kq -->r1bq1rk1/pppp1ppp/2n2n2/1Bb1p3/4P3/2P2N2/PP1P1PPP/RNBQ1RK1 w - - 1249 | 1250 | 1251 | 1252 | 1253 | 1254 | 1255 | O-O 1256 | 1257 | 1258 | 1259 | 1260 | 1261 | r1bqk2r/pppp1ppp/1bn2n2/1B2p3/4P3/2P2N2/PP1P1PPP/RNBQ1RK1 w kq - 1262 | 1263 | 1264 | 67 1265 | 1266 | 1267 | 1268 | 1269 | 1270 | r1bqk2r/pppp1ppp/2n2n2/1Bb1p3/4P3/2P2N2/PP1P1PPP/RNBQ1RK1 b kq -->r1bqk2r/pppp1ppp/1bn2n2/1B2p3/4P3/2P2N2/PP1P1PPP/RNBQ1RK1 w kq - 1271 | 1272 | 1273 | 1274 | 1275 | 1276 | 1277 | Bb6 1278 | 1279 | 1280 | 1281 | 1282 | 1283 | r1bqk2r/pppp1ppp/5n2/1Bb1p3/3nP3/2N2N2/PPPP1PPP/R1BQ1RK1 w kq - 1284 | 1285 | 1286 | 34 1287 | 1288 | 1289 | 1290 | 1291 | 1292 | r1bqk2r/pppp1ppp/2n2n2/1Bb1p3/4P3/2N2N2/PPPP1PPP/R1BQ1RK1 b kq -->r1bqk2r/pppp1ppp/5n2/1Bb1p3/3nP3/2N2N2/PPPP1PPP/R1BQ1RK1 w kq - 1293 | 1294 | 1295 | 1296 | 1297 | 1298 | 1299 | Nd4 1300 | 1301 | 1302 | 1303 | 1304 | 1305 | r1bqkb1r/pppp1ppp/2nn4/1B2N3/8/8/PPPP1PPP/RNBQR1K1 b kq - 1306 | 1307 | 1308 | 38 1309 | 1310 | 1311 | 1312 | 1313 | 1314 | r1bqkb1r/pppp1ppp/2nn4/1B2p3/8/5N2/PPPP1PPP/RNBQR1K1 w kq -->r1bqkb1r/pppp1ppp/2nn4/1B2N3/8/8/PPPP1PPP/RNBQR1K1 b kq - 1315 | 1316 | 1317 | 1318 | 1319 | 1320 | 1321 | Nxe5 1322 | 1323 | 1324 | 1325 | 1326 | 1327 | r1bqk1nr/1pp1bppp/p1p5/4N3/4P3/8/PPPP1PPP/RNBQ1RK1 b kq - 1328 | 1329 | 1330 | 27 1331 | 1332 | 1333 | 1334 | 1335 | 1336 | r1bqk1nr/1pp1bppp/p1p5/4p3/4P3/5N2/PPPP1PPP/RNBQ1RK1 w kq -->r1bqk1nr/1pp1bppp/p1p5/4N3/4P3/8/PPPP1PPP/RNBQ1RK1 b kq - 1337 | 1338 | 1339 | 1340 | 1341 | 1342 | 1343 | Nxe5 1344 | 1345 | 1346 | 1347 | 1348 | 1349 | r1bq1rk1/pppp1ppp/2n2n2/1Bb1p3/3PP3/2P2N2/PP3PPP/RNBQ1RK1 b - - 1350 | 1351 | 1352 | 48 1353 | 1354 | 1355 | 1356 | 1357 | 1358 | r1bq1rk1/pppp1ppp/2n2n2/1Bb1p3/4P3/2P2N2/PP1P1PPP/RNBQ1RK1 w - -->r1bq1rk1/pppp1ppp/2n2n2/1Bb1p3/3PP3/2P2N2/PP3PPP/RNBQ1RK1 b - - 1359 | 1360 | 1361 | 1362 | 1363 | 1364 | 1365 | d4 1366 | 1367 | 1368 | 1369 | 1370 | 1371 | r1bq1rk1/pppp1ppp/2n2n2/1Bb1p3/4P3/2P2N2/PP1P1PPP/RNBQR1K1 b - - 1372 | 1373 | 1374 | 37 1375 | 1376 | 1377 | 1378 | 1379 | 1380 | r1bq1rk1/pppp1ppp/2n2n2/1Bb1p3/4P3/2P2N2/PP1P1PPP/RNBQ1RK1 w - -->r1bq1rk1/pppp1ppp/2n2n2/1Bb1p3/4P3/2P2N2/PP1P1PPP/RNBQR1K1 b - - 1381 | 1382 | 1383 | 1384 | 1385 | 1386 | 1387 | Re1 1388 | 1389 | 1390 | 1391 | 1392 | 1393 | r1bqk2r/pppp1ppp/1bB2n2/4p3/4P3/2P2N2/PP1P1PPP/RNBQ1RK1 b kq - 1394 | 1395 | 1396 | 35 1397 | 1398 | 1399 | 1400 | 1401 | 1402 | r1bqk2r/pppp1ppp/1bn2n2/1B2p3/4P3/2P2N2/PP1P1PPP/RNBQ1RK1 w kq -->r1bqk2r/pppp1ppp/1bB2n2/4p3/4P3/2P2N2/PP1P1PPP/RNBQ1RK1 b kq - 1403 | 1404 | 1405 | 1406 | 1407 | 1408 | 1409 | Bxc6 1410 | 1411 | 1412 | 1413 | 1414 | 1415 | r1bqkb1r/pppp1ppp/3n4/1B2n3/8/8/PPPP1PPP/RNBQR1K1 w kq - 1416 | 1417 | 1418 | 36 1419 | 1420 | 1421 | 1422 | 1423 | 1424 | r1bqkb1r/pppp1ppp/2nn4/1B2N3/8/8/PPPP1PPP/RNBQR1K1 b kq -->r1bqkb1r/pppp1ppp/3n4/1B2n3/8/8/PPPP1PPP/RNBQR1K1 w kq - 1425 | 1426 | 1427 | 1428 | 1429 | 1430 | 1431 | Nxe5 1432 | 1433 | 1434 | 1435 | 1436 | 1437 | r1bqk2r/ppppbppp/2nn4/1B2N3/8/8/PPPP1PPP/RNBQR1K1 w kq - 1438 | 1439 | 1440 | 38 1441 | 1442 | 1443 | 1444 | 1445 | 1446 | r1bqkb1r/pppp1ppp/2nn4/1B2N3/8/8/PPPP1PPP/RNBQR1K1 b kq -->r1bqk2r/ppppbppp/2nn4/1B2N3/8/8/PPPP1PPP/RNBQR1K1 w kq - 1447 | 1448 | 1449 | 1450 | 1451 | 1452 | 1453 | Be7 1454 | 1455 | 1456 | 1457 | 1458 | 1459 | r1bq1rk1/pppp1ppp/1bn2n2/1B2p3/3PP3/2P2N2/PP3PPP/RNBQ1RK1 w - - 1460 | 1461 | 1462 | 42 1463 | 1464 | 1465 | 1466 | 1467 | 1468 | r1bq1rk1/pppp1ppp/2n2n2/1Bb1p3/3PP3/2P2N2/PP3PPP/RNBQ1RK1 b - -->r1bq1rk1/pppp1ppp/1bn2n2/1B2p3/3PP3/2P2N2/PP3PPP/RNBQ1RK1 w - - 1469 | 1470 | 1471 | 1472 | 1473 | 1474 | 1475 | Bb6 1476 | 1477 | 1478 | 1479 | 1480 | 1481 | r1bqkb1r/pppp1ppp/3n4/1B2R3/8/8/PPPP1PPP/RNBQ2K1 b kq - 1482 | 1483 | 1484 | ♜ · ♝ ♛ ♚ ♝ · ♜ 1485 | ♟ ♟ ♟ ♟ · ♟ ♟ ♟ 1486 | · · · ♞ · · · · 1487 | · ♗ · · ♖ · · · 1488 | · · · · · · · · 1489 | · · · · · · · · 1490 | ♙ ♙ ♙ ♙ · ♙ ♙ ♙ 1491 | ♖ ♘ ♗ ♕ · · ♔ · 1492 | 1493 | 1494 | 1495 | 1496 | 1497 | r1bqkb1r/pppp1ppp/3n4/1B2n3/8/8/PPPP1PPP/RNBQR1K1 w kq -->r1bqkb1r/pppp1ppp/3n4/1B2R3/8/8/PPPP1PPP/RNBQ2K1 b kq - 1498 | 1499 | 1500 | 1501 | 1502 | 1503 | 1504 | Rxe5+ 1505 | 1506 | 1507 | 1508 | 1509 | 1510 | r1bqk2r/ppppbppp/2nn4/4N3/8/8/PPPP1PPP/RNBQRBK1 b kq - 1511 | 1512 | 1513 | ♜ · ♝ ♛ ♚ · · ♜ 1514 | ♟ ♟ ♟ ♟ ♝ ♟ ♟ ♟ 1515 | · · ♞ ♞ · · · · 1516 | · · · · ♘ · · · 1517 | · · · · · · · · 1518 | · · · · · · · · 1519 | ♙ ♙ ♙ ♙ · ♙ ♙ ♙ 1520 | ♖ ♘ ♗ ♕ ♖ ♗ ♔ · 1521 | 1522 | 1523 | 1524 | 1525 | 1526 | r1bqk2r/ppppbppp/2nn4/1B2N3/8/8/PPPP1PPP/RNBQR1K1 w kq -->r1bqk2r/ppppbppp/2nn4/4N3/8/8/PPPP1PPP/RNBQRBK1 b kq - 1527 | 1528 | 1529 | 1530 | 1531 | 1532 | 1533 | Bf1 1534 | 1535 | 1536 | 1537 | 1538 | 1539 | --------------------------------------------------------------------------------