From: QueensGambit Date: Wed, 6 Jan 2021 23:41:37 +0000 (+0100) Subject: Updated ffish.js to 0.5.0 X-Git-Url: http://winboard.nl/cgi-bin?a=commitdiff_plain;h=56de2a24695141482b67b91a0cba0ca544e1e206;p=fairystockfish.git Updated ffish.js to 0.5.0 * fixed parsing PGN mainline_moves() with nested atlernative lines and glyphs * mapped variant "standard" or "Standard" to "chess" * updated README.md + added board.toString() + added board.toVerboseString() + added "Syrov - Dgebuadze.pgn" as unit test pgn-file --- diff --git a/src/ffishjs.cpp b/src/ffishjs.cpp index 448b80f..c720643 100644 --- a/src/ffishjs.cpp +++ b/src/ffishjs.cpp @@ -59,7 +59,7 @@ inline void save_pop_back(std::string& s) { } const Variant* get_variant(const std::string& uciVariant) { - if (uciVariant.size() == 0) + if (uciVariant.size() == 0 || uciVariant == "Standard" || uciVariant == "standard") return variants.find("chess")->second; return variants.find(uciVariant)->second; } @@ -296,9 +296,32 @@ public: return pocket; } - // TODO: return board in ascii notation - // static std::string get_string_from_instance(const Board& board) { - // } + std::string to_string() { + std::string stringBoard; + for (Rank r = pos.max_rank(); r >= RANK_1; --r) { + for (File f = FILE_A; f <= pos.max_file(); ++f) { + if (f != FILE_A) + stringBoard += " "; + const Piece p = pos.piece_on(make_square(f, r)); + switch(p) { + case NO_PIECE: + stringBoard += '.'; + break; + default: + stringBoard += pos.piece_to_char()[p]; + } + } + if (r != RANK_1) + stringBoard += "\n"; + } + return stringBoard; + } + + std::string to_verbose_string() { + std::stringstream ss; + operator<<(ss, pos); + return ss.str(); + } private: void resetStates() { @@ -409,6 +432,20 @@ public: }; +bool skip_comment(const std::string& pgn, size_t& curIdx, size_t& lineEnd) { + if (pgn[curIdx] == '{') { + // skip comment + curIdx = pgn.find('}', curIdx); + if (curIdx == std::string::npos) { + std::cerr << "Missing '}' for move comment while reading pgn." << std::endl; + return false; + } + if (curIdx > lineEnd) + lineEnd = pgn.find('\n', curIdx); + } + return true; +} + Game read_game_pgn(std::string pgn) { Game game; size_t lineStart = 0; @@ -418,7 +455,7 @@ Game read_game_pgn(std::string pgn) { size_t lineEnd = pgn.find('\n', lineStart); if (lineEnd == std::string::npos) - lineEnd = pgn.size(); + lineEnd = pgn.size(); if (!headersParsed && pgn[lineStart] == '[') { // parse header @@ -444,7 +481,7 @@ Game read_game_pgn(std::string pgn) { it = game.header.find("FEN"); if (it != game.header.end()) - game.fen = it->second; + game.fen = it->second; game.board = std::make_unique(game.variant, game.fen, game.is960); game.parsedGame = true; @@ -454,39 +491,50 @@ Game read_game_pgn(std::string pgn) { size_t curIdx = lineStart; while (curIdx <= lineEnd) { if (pgn[curIdx] == '*') - return game; - - while (pgn[curIdx] == '{') { - // skip comment - curIdx = pgn.find('}', curIdx); - if (curIdx == std::string::npos) { - std::cerr << "Missing '}' for move comment while reading pgn." << std::endl; - return game; - } - curIdx += 2; + return game; + + if (!skip_comment(pgn, curIdx, lineEnd)) + return game; + + // Movetext RAV (Recursive Annotation Variation) + size_t openedRAV = 0; + if (pgn[curIdx] == '(') { + openedRAV = 1; + ++curIdx; } - while (pgn[curIdx] == '(') { - // skip comment - curIdx = pgn.find(')', curIdx); - if (curIdx == std::string::npos) { - std::cerr << "Missing ')' for move comment while reading pgn." << std::endl; - return game; + while (openedRAV != 0) { + switch (pgn[curIdx]) { + case '(': + ++openedRAV; + break; + case ')': + --openedRAV; + break; + case '{': + if (!skip_comment(pgn, curIdx, lineEnd)) + return game; + default: ; // pass } - curIdx += 2; + ++curIdx; + } + + if (pgn[curIdx] == '$') { + // we are at a glyph + curIdx = pgn.find(' ', curIdx); } if (pgn[curIdx] >= '0' && pgn[curIdx] <= '9') { // we are at a move number -> look for next point curIdx = pgn.find('.', curIdx); if (curIdx == std::string::npos) - break; + break; ++curIdx; // increment if we're at a space while (curIdx < pgn.size() && pgn[curIdx] == ' ') - ++curIdx; + ++curIdx; // increment if we're at a point while (curIdx < pgn.size() && pgn[curIdx] == '.') - ++curIdx; + ++curIdx; } // extract sanMove size_t sanMoveEnd = std::min(pgn.find(' ', curIdx), lineEnd); @@ -496,7 +544,7 @@ Game read_game_pgn(std::string pgn) { size_t annotationChar1 = sanMove.find('?'); size_t annotationChar2 = sanMove.find('!'); if (annotationChar1 != std::string::npos || annotationChar2 != std::string::npos) - sanMove = sanMove.substr(0, std::min(annotationChar1, annotationChar2)); + sanMove = sanMove.substr(0, std::min(annotationChar1, annotationChar2)); game.board->push_san(sanMove); } curIdx = sanMoveEnd+1; @@ -505,7 +553,7 @@ Game read_game_pgn(std::string pgn) { lineStart = lineEnd+1; if (lineStart >= pgn.size()) - return game; + return game; } return game; } @@ -545,7 +593,9 @@ EMSCRIPTEN_BINDINGS(ffish_js) { .function("pushMoves", &Board::push_moves) .function("pushSanMoves", select_overload(&Board::push_san_moves)) .function("pushSanMoves", select_overload(&Board::push_san_moves)) - .function("pocket", &Board::pocket); + .function("pocket", &Board::pocket) + .function("toString", &Board::to_string) + .function("toVerboseString", &Board::to_verbose_string); class_("Game") .function("headerKeys", &Game::header_keys) .function("headers", &Game::headers) diff --git a/tests/js/README.md b/tests/js/README.md index e12e569..f938a79 100644 --- a/tests/js/README.md +++ b/tests/js/README.md @@ -61,7 +61,7 @@ Show all available variants supported by _Fairy-Stockfish_ and **ffish.js**. ffish.variants() ``` ``` ->> 3check 5check ai-wok almost amazon antichess armageddon asean ataxx breakthrough bughouse cambodian\ +3check 5check ai-wok almost amazon antichess armageddon asean ataxx breakthrough bughouse cambodian\ capablanca capahouse caparandom centaur chancellor chess chessgi chigorin clobber clobber10 codrus courier\ crazyhouse dobutsu embassy euroshogi extinction fairy fischerandom gardner giveaway gorogoro gothic grand\ hoppelpoppel horde janggi janggicasual janggimodern janggitraditional janus jesonmor judkins karouk kinglet\ @@ -70,24 +70,6 @@ minixiangqi modern newzealand nocastle normal placement pocketknight racingkings shatranj shogi shouse sittuyin suicide supply threekings xiangqi ``` -## Custom variants - -Fairy-Stockfish also allows defining custom variants by loading a configuration file. - -See e.g. the configuration for **connect4**, **tictactoe** or **janggihouse** in [variants.ini](https://github.com/ianfab/Fairy-Stockfish/blob/master/src/variants.ini). -```javascript -fs = require('fs'); -let configFilePath = './variants.ini'; - fs.readFile(configFilePath, 'utf8', function (err,data) { - if (err) { - return console.log(err); - } - ffish.loadVariantConfig(data) - let board = new ffish.Board("tictactoe"); - board.delete(); - }); -``` - ### Board object Create a new variant board from its default starting position. @@ -112,9 +94,62 @@ else { Alternatively, you can initialize a board with a custom FEN directly: ```javascript -let board2 = new ffish.Board("crazyhouse", "rnb1kb1r/ppp2ppp/4pn2/8/3P4/2N2Q2/PPP2PPP/R1B1KB1R/QPnp b KQkq - 0 6"); +let board2 = new ffish.Board("chess", "rnb1kbnr/ppp1pppp/8/3q4/8/8/PPPP1PPP/RNBQKBNR w KQkq - 0 3"); ``` +### ASCII board + +You can show an ASCII representation of the board using the `toString()` method + +```javascript +let board = new ffish.Board("chess", "rnb1kbnr/ppp1pppp/8/3q4/8/8/PPPP1PPP/RNBQKBNR w KQkq - 0 3"); +console.log(board.toString()) +``` +``` +r n b . k b n r +p p p . p p p p +. . . . . . . . +. . . q . . . . +. . . . . . . . +. . . . . . . . +P P P P . P P P +R N B Q K B N R +``` + +or a more detailed representation using `.toVerboseString()`. + +```javascript +let board = new ffish.Board("chess", "rnb1kbnr/ppp1pppp/8/3q4/8/8/PPPP1PPP/RNBQKBNR w KQkq - 0 3"); +console.log(board.toVerboseString()) +``` +``` ++---+---+---+---+---+---+---+---+ +| r | n | b | | k | b | n | r |8 ++---+---+---+---+---+---+---+---+ +| p | p | p | | p | p | p | p |7 ++---+---+---+---+---+---+---+---+ +| | | | | | | | |6 ++---+---+---+---+---+---+---+---+ +| | | | q | | | | |5 ++---+---+---+---+---+---+---+---+ +| | | | | | | | |4 ++---+---+---+---+---+---+---+---+ +| | | | | | | | |3 ++---+---+---+---+---+---+---+---+ +| P | P | P | P | | P | P | P |2 ++---+---+---+---+---+---+---+---+ +| R | N | B | Q | K | B | N | R |1 * ++---+---+---+---+---+---+---+---+ + a b c d e f g h + +Fen: rnb1kbnr/ppp1pppp/8/3q4/8/8/PPPP1PPP/RNBQKBNR w KQkq - 0 3 +Sfen: rnb1kbnr/ppp1pppp/8/3q4/8/8/PPPP1PPP/RNBQKBNR b - 5 +Key: AE7D48F19DB356CD +Checkers: +``` + +## Move generation and application + Add a new move: ```javascript board.push("g2g4"); @@ -130,6 +165,8 @@ for (var i = 0; i < legalMovesSan.length; i++) { } ``` +## Memory management + Unfortunately, it is impossible for Emscripten to call the destructor on C++ objects. Therefore, you need to call `.delete()` to free the heap memory of an object. ```javascript @@ -165,6 +202,24 @@ fs.readFile(pgnFilePath, 'utf8', function (err,data) { } ``` +## Custom variants + +Fairy-Stockfish also allows defining custom variants by loading a configuration file. + +See e.g. the configuration for **connect4**, **tictactoe** or **janggihouse** in [variants.ini](https://github.com/ianfab/Fairy-Stockfish/blob/master/src/variants.ini). +```javascript +fs = require('fs'); +let configFilePath = './variants.ini'; + fs.readFile(configFilePath, 'utf8', function (err,data) { + if (err) { + return console.log(err); + } + ffish.loadVariantConfig(data) + let board = new ffish.Board("tictactoe"); + board.delete(); + }); +``` + ## Remaining features For an example of each available function see [test.js](https://github.com/ianfab/Fairy-Stockfish/blob/master/tests/js/test.js). diff --git a/tests/js/package.json b/tests/js/package.json index 9bda065..5d7c798 100644 --- a/tests/js/package.json +++ b/tests/js/package.json @@ -1,6 +1,6 @@ { "name": "ffish", - "version": "0.4.7", + "version": "0.5.0", "description": "A high performance WebAssembly chess variant library based on Fairy-Stockfish", "main": "ffish.js", "scripts": { diff --git a/tests/js/test.js b/tests/js/test.js index f39b26c..79fcf34 100644 --- a/tests/js/test.js +++ b/tests/js/test.js @@ -395,6 +395,28 @@ describe('board.pocket(turn)', function () { }); }); +describe('board.toString()', function () { + it("it returns a compact string representation of the board.", () => { + const board = new ffish.Board("chess", "rnb1kbnr/ppp1pppp/8/3q4/8/8/PPPP1PPP/RNBQKBNR w KQkq - 0 3"); + chai.expect(board.toString()).to.equal("r n b . k b n r\np p p . p p p p\n. . . . . . . .\n. . . q . . . .\n. . . . . . . .\n. . . . . . . .\nP P P P . P P P\nR N B Q K B N R"); + board.delete(); + const board2 = new ffish.Board("xiangqi"); + chai.expect(board2.toString()).to.equal("r n b a k a b n r\n. . . . . . . . .\n. c . . . . . c .\np . p . p . p . p\n. . . . . . . . .\n. . . . . . . . .\nP . P . P . P . P\n. C . . . . . C .\n. . . . . . . . .\nR N B A K A B N R"); + board2.delete(); + }); +}); + +describe('board.toVerboseString()', function () { + it("it returns a verbose string representation of the board.", () => { + const board = new ffish.Board("chess", "rnb1kbnr/ppp1pppp/8/3q4/8/8/PPPP1PPP/RNBQKBNR w KQkq - 0 3"); + chai.expect(board.toVerboseString()).to.equal("\n +---+---+---+---+---+---+---+---+\n | r | n | b | | k | b | n | r |8 \n +---+---+---+---+---+---+---+---+\n | p | p | p | | p | p | p | p |7\n +---+---+---+---+---+---+---+---+\n | | | | | | | | |6\n +---+---+---+---+---+---+---+---+\n | | | | q | | | | |5\n +---+---+---+---+---+---+---+---+\n | | | | | | | | |4\n +---+---+---+---+---+---+---+---+\n | | | | | | | | |3\n +---+---+---+---+---+---+---+---+\n | P | P | P | P | | P | P | P |2\n +---+---+---+---+---+---+---+---+\n | R | N | B | Q | K | B | N | R |1 *\n +---+---+---+---+---+---+---+---+\n a b c d e f g h\n\nFen: rnb1kbnr/ppp1pppp/8/3q4/8/8/PPPP1PPP/RNBQKBNR w KQkq - 0 3\nSfen: rnb1kbnr/ppp1pppp/8/3q4/8/8/PPPP1PPP/RNBQKBNR b - 5\nKey: AE7D48F19DB356CD\nCheckers: ") + board.delete(); + const board2 = new ffish.Board("xiangqi"); + chai.expect(board2.toVerboseString()).to.equal("\n +---+---+---+---+---+---+---+---+---+\n | r | n | b | a | k | a | b | n | r |10 \n +---+---+---+---+---+---+---+---+---+\n | | | | | | | | | |9\n +---+---+---+---+---+---+---+---+---+\n | | c | | | | | | c | |8\n +---+---+---+---+---+---+---+---+---+\n | p | | p | | p | | p | | p |7\n +---+---+---+---+---+---+---+---+---+\n | | | | | | | | | |6\n +---+---+---+---+---+---+---+---+---+\n | | | | | | | | | |5\n +---+---+---+---+---+---+---+---+---+\n | P | | P | | P | | P | | P |4\n +---+---+---+---+---+---+---+---+---+\n | | C | | | | | | C | |3\n +---+---+---+---+---+---+---+---+---+\n | | | | | | | | | |2\n +---+---+---+---+---+---+---+---+---+\n | R | N | B | A | K | A | B | N | R |1 *\n +---+---+---+---+---+---+---+---+---+\n a b c d e f g h i\n\nFen: rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR w - - 0 1\nSfen: rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR b - 1\nKey: 1FBADA178B89E4C3\nCheckers: "); + board2.delete(); + }); +}); + describe('ffish.info()', function () { it("it returns the version of the Fairy-Stockfish binary", () => { chai.expect(ffish.info()).to.be.a('string'); @@ -471,11 +493,13 @@ describe('ffish.validateFen(fen, uciVariant)', function () { describe('ffish.readGamePGN(pgn)', function () { it("it reads a pgn string and returns a game object", () => { fs = require('fs'); - let pgnFiles = ['deep_blue_kasparov_1997.pgn', 'lichess_pgn_2018.12.21_JannLee_vs_CrazyAra.j9eQS4TF.pgn', 'c60_ruy_lopez.pgn', 'pychess-variants_zJxHRVm1.pgn'] + let pgnFiles = ['deep_blue_kasparov_1997.pgn', 'lichess_pgn_2018.12.21_JannLee_vs_CrazyAra.j9eQS4TF.pgn', 'c60_ruy_lopez.pgn', 'pychess-variants_zJxHRVm1.pgn', 'Syrov - Dgebuadze.pgn'] + let expectedFens = ["1r6/5kp1/RqQb1p1p/1p1PpP2/1Pp1B3/2P4P/6P1/5K2 b - - 14 45", "3r2kr/2pb1Q2/4ppp1/3pN2p/1P1P4/3PbP2/P1P3PP/6NK[PPqrrbbnn] b - - 1 37", "r1bqkbnr/pppp1ppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R b KQkq - 3 3", - "r1bQkb1r/ppp1pppp/2P5/2n2q2/8/2N2N2/PPP2PPP/R1BEKB1R[Hh] b KQACEFHkqacefh - 0 8"] + "r1bQkb1r/ppp1pppp/2P5/2n2q2/8/2N2N2/PPP2PPP/R1BEKB1R[Hh] b KQACEFHkqacefh - 0 8", + "5rk1/4p3/2p3rR/2p1P3/2Pp1B2/1P1P2P1/2N1n3/6K1 w - - 1 44"] for (let idx = 0; idx < pgnFiles.length; ++idx) { let pgnFilePath = pgnDir + pgnFiles[idx]; diff --git a/tests/pgn/Syrov - Dgebuadze.pgn b/tests/pgn/Syrov - Dgebuadze.pgn new file mode 100644 index 0000000..8b30644 --- /dev/null +++ b/tests/pgn/Syrov - Dgebuadze.pgn @@ -0,0 +1,137 @@ +[Event "RLP-Open R7"] +[Site "?"] +[Date "????.??.??"] +[Round "1.2"] +[White "Syrov, Arkadi"] +[Black "Dgebuadze, Alexandre"] +[Result "0-1"] +[ECO "B31"] +[WhiteElo "2291"] +[BlackElo "2508"] +[Annotator "Syrov, Arkadi"] +[PlyCount "86"] + +1. e4 {[%emt 0:00:01]} c5 {[%emt 0:00:21] keine völlige Überraschung, da ich +gesehen habe, dass er schon c5 gespielt hat, aber nur gegen Morra. Ich hatte +hauptsächlich mit Französisch gerechnet.} 2. Nf3 {[%emt 0:00:05]} Nc6 { +[%emt 0:00:04]} 3. Bb5 {[%emt 0:00:04]} g6 {[%emt 0:00:09]} 4. Bxc6 {[%emt 0: +00:05]} bxc6 {[%emt 0:00:07]} 5. O-O {[%emt 0:00:05]} Bg7 {[%emt 0:00:16]} 6. +Re1 {[%emt 0:00:05] jetzt begann er lange zu denken, was ich nicht erwartet +habe. Bis hierher habe ich gefühlt 10 Partien in der Datenbank.} d5 {[%emt 0: +21:13] das ist nicht die Hauptvariante. Während ich herumlief und auf seinen +Zug wartete, habe ich versucht mich an die Theorie nach Sh6 c3 zu erinnern. +Von d5 wusste ich nichts, also reagierte ich Standardmäßig.} 7. d3 {[%emt 0: +02:47]} Bg4 {[%emt 0:01:22]} 8. Nbd2 {[%emt 0:03:46] Im nachhinein ist das +eine schlechte Entscheidung. Ich hätte gleich h3 spielen sollen. Ich wollte +auf f3 mit dem Springer schlagen und habe mich selbst ausgetrixt, denn er +bekommt eine neue Option.} (8. h3 Bxf3 9. Qxf3 $14 {sollte etwas besser sein.}) +8... Nf6 {[%emt 0:03:45]} 9. e5 {[%emt 0:05:32]} (9. h3 {wäre glaube ich +immer noch besser gewesen und dann wieder mit der Dame auf f3 schlagen. Aber +ich habe die ganze Idee mit Le6 nicht betrachtet.}) 9... Nd7 {[%emt 0:02:01]} +10. h3 {[%emt 0:00:14]} Be6 {[%emt 0:09:32]} 11. c4 $2 {[%emt 0:17:01] die +Standardidee um die Doppelbauern festzulegen.} (11. Ng5 $1 {war meine +Alternative. Ich habe es wegen:} Nxe5 {nicht gespielt.} (11... Nf8 {war der +Plan meines Gegners, was auch sinnvoll aussieht. Aber konkret hat Weiß eine +starke Antwort (Natürlich habe ich alles folgende nicht gesehen):} 12. Nb3 $1 +h6 13. Nxe6 Nxe6 14. Be3 Bxe5 (14... Qb6 15. f4 $14 {[%csl Gc5][%cal Gd1f3, +Gf3f2]} a5 (15... O-O 16. Qf3 a5 17. Qf2 d4 18. Bc1 $16 {ist einfach traurig +für Schwarz}) 16. Qf3 a4 17. Nxc5 $1 Nxc5 18. Qf2 Nxd3 19. cxd3 Qb5 20. Bc5 e6 +(20... Qxd3 $2 21. Bxe7 $3 Kxe7 22. Qc5+ $18) 21. d4 $14 {[%csl Gc6]}) 15. Nxc5 +Nxc5 16. Bxc5 Bf6 17. Qd2 $1 $14 {Schwarz kann nicht rochieren, da h6 hängt +und es ist klar, dass Weiß einen kleinen Vorteil haben sollte.}) 12. f4 Nd7 +13. Nxe6 (13. Rxe6 fxe6 14. Nxe6 Qb6 15. Nxg7+ Kf7 {schien auch nicht +funktionieren. Ich habe keine Figuren, die im Angriff sind.}) 13... fxe6 14. +Rxe6 O-O {und ich wusste nicht was das soll. Denn der Bauer auf f4 ist Schwach, +ich dachte während der Partie, dass Weiß hier schlechter steht. Was +anscheinend eine riesige Fehleinschätzung ist. Denn nach} (14... Rc8 15. Nf3 +c4 {soll Schwarz probieren, aber es ist immer noch besser für Weiß} 16. dxc4 +Nc5 17. Re1 $14) 15. Nf3 {hängt c6 und e7 und nach} Rc8 (15... Qc7 16. Rxe7 +Rae8 17. Qe2 Rxe7 18. Qxe7 $16 {ist einfach ein Bauer}) 16. Qe1 Bf6 17. f5 $1 { +hat Schwarz riesige Probleme.}) (11. d4 {habe ich auch kurz überlegt, aber +ich habe nicht ganz verstanden, was das mir bringt, außer die Stellung zu +öffnen, was meinem Gegner zugute kommen sollte.}) (11. b3 {war auch eine +Möglichkeit an der ich überlegt habe und dann ohne c4 spielen. Oder in einem +besseren Moment c4 spielen. Vielleicht wäre das eine bessere Möglichkeit.}) ( +11. Qe2 h6 12. b3 {[%cal Ga2a4] und ohne c4 spielen sieht auch sehr gut aus.}) +11... h6 {[%emt 0:07:58] ein logischer Zug um Sg5 aus der Stellung zu nehmen. +Und manchmal wird g5 zur Idee.} 12. Qe2 {[%emt 0:00:48] sah logisch aus, um c4 +zu decken, den e5 zu decken und dann meinen Problemspringer auf d2 zu +überführen.} Qb6 {[%emt 0:02:13] ein etwas mysteriöser Zug. Die Idee ist +wahrscheinlich in manchen Varianten Db4 zu haben und b2 im Visier zu behalten. +Ich war hier ehrlich gesagt etwas verloren und wusste nicht wirklich was ich +als nächstes machen sollte und begann etwas kreativ zu werden, bis ich alle +meine Ideen selbst wiederlegt habe.} 13. Nb1 {[%emt 0:13:59][%cal Gb1c3,Gb2b3, +Gc3a4] wenn ich noch einen Zug machen darf, steht Schwarz glaube ich ganz +schlecht, aber den gibt mir Schwarz natürlich nicht.} (13. a4 a5 14. Ra3 { +war eine sau komische Idee, die ich hatte um den c5 unter Druck zu setzen, +aber ich war mir über die Bewertung der Schlussstellung nicht sicher.} Nb8 { +ich glaube Schwarz sollte das schwache b4 Feld ausnutzen.} 15. Rb3 Qa7 { +hier steht die Dame dachte ich am besten} (15... Qc7 16. Rc3 Na6 17. b3 Nb4 18. +Ba3 {habe ich vielleicht motive mit nimmt auf d5 und d4, da die Dame auf c7 in +der Turmlinie steht.}) 16. Rc3 Na6 17. b3 Nb4 18. Ba3 O-O {ich kann den c5 +nicht noch mehr angreifen, da nach Tec1 d4 kommt und ich weiß nicht, was ich +weiter machen soll.}) (13. b3 a5 {hat mir nicht gefallen, da ich entweder a4 +spielen muss, oder a4 zulassen muss. In beiden fällen hat mir die Perspektive +nicht gefallen, da entweder b4 sehr schwach wird und Sb4 und Lf5 kommen, oder +all dass und der b3 wird schwach. (Bzw a2, wenn ich nicht auf b3 mit dem +Bauern nehme).}) (13. Nf1 {ich wusste nicht, wohin der Springer von hier gehen +will.}) (13. Nb3 {ich dachte das läuft einfach in a5 und a4 mit Tempo.}) 13... +a5 {[%emt 0:00:21] sonst käme Sc3 und auf a5 dann, b3 oder Sa4.} 14. Bf4 { +[%emt 0:07:12] wieder war ich etwas verloren und hatte keine Ahnung wie ich +meine Figuren hinstellen soll. Es ist klar, dass er a4 im nächsten Zug machen +wird und was ich mache ist mir ein Rätsel.} a4 {[%emt 0:02:34]} 15. Na3 { +[%emt 0:02:47] ich habe wirklich keine Ahnung was hier richtig ist und was +nicht.} g5 {[%emt 0:03:33]} 16. Bg3 {[%emt 0:03:12]} O-O {[%emt 0:09:10]} ( +16... g4 17. hxg4 Bxg4 18. Rab1 {[%cal Ge2e3] ich dachte nicht, dass es so +viel für Schwarz bringt.}) 17. Rab1 {[%emt 0:00:59] um b2 zu decken, damit +sich die Dame bewegen kann. Vielleicht wäre h4 sofort richtig gewesen!?} Rfe8 +{[%emt 0:02:02]} (17... Bf5 $1 {gefolgt von e6 sieht stark aus} 18. Nc2 e6 19. +Ne3 Bg6 $15) 18. h4 {[%emt 0:01:14]} f6 {[%emt 0:04:19]} (18... g4 19. Nh2 h5 +20. f3 {hier war ich ziemlich optimistisch gute Chancen zu haben.}) {Hier habe +ich überlegt, dass ich eigentlich nichts machen will. Ich will glaube ich +alles so lassen wie es ist. Aber ich konnte einfach keinen Zug finden, der +irgendwie sinnvoll ist. Im nachhinein sieht Sc2 gut aus.} 19. hxg5 {[%emt 0:05: +39] ich glaube das ist der Verlustzug. Ich wollte einfach hg, hg einschieben, +und dann weiterschauen. Aber das hat ein Problem...} (19. Nc2 {und die +Stellung ist noch spielbar}) 19... fxg5 {[%emt 0:01:10] nachdem dieser Zug kam, +verstand ich, dass ich in riesigen Problemen stecke. Es kommt einfach Tf8-f5 +und was mache ich?} 20. Nh2 {[%emt 0:00:59] ich wollte dem Lg4 und Tf8-Motiv +aus dem Weg gehen. Und vielleicht Dh5. Ich wollte noch viellecht f4 spielen um +etwas Gegenspiel zu bekommen.} (20. Nc2 {hätte ich spielen sollen} Rf8 21. +Red1 Bg4 22. e6 Bxf3 23. gxf3 Nf6 24. f4 gxf4 25. Bxf4 Qd8 $15 {[%cal Gd8e8, +Ge8h5] aber das soll Schwarz noch finden.}) 20... Rf8 {[%emt 0:00:51]} 21. Qe3 +{[%emt 0:06:01]} Rf5 {[%emt 0:02:37]} 22. f4 {[%emt 0:00:14] sonst fliegt e5 +ersatzlos und damit auch meine Stellung, dachte ich. Wenn ich es nicht mache, +geht es noch halbwegs, laut dem Blechheinie} (22. Nc2 $15) 22... Raf8 {[%emt 0: +01:40]} 23. fxg5 {[%emt 0:01:14] auch glaube ich ohne wirklich sinnvolle +Alternative} Rxg5 {[%emt 0:00:26]} 24. Bf4 {[%emt 0:00:42]} Rg6 {[%emt 0:07:46] +} (24... Rxf4 25. Qxf4 Bxe5 26. Qh4 {und ich dachte ich hätte noch +gegenchancen.}) (24... Bxe5 {war eine Idee, die ich gar nicht gesehen habe. +Aber ich habe noch eine Möglichkeit eine völlige Chaos-Stellung zu erreichen: +} 25. Bxg5 Bd4 26. Qxd4 cxd4 27. Bxe7 {und was hier abgeht, weiß nur +Stockfish.}) 25. Nf3 {[%emt 0:03:59] ich glaube das verliert forciert.} (25. +Re2 {ist vielleicht der Zug um weiterzuspielen. Jetzt kann ich vielleicht den +Turm nach f1 stellen und ich glaube ich verliere nichts sofort.}) 25... d4 { +[%emt 0:01:46]} (25... Rg4 26. Bh2 d4 27. Qe2 {ist glaube ich noch spielbar}) +26. Qd2 {[%emt 0:01:38]} Qb4 {[%emt 0:02:22]} (26... Rg4 27. Re4 (27. Bxh6 $2 +Rxf3 28. Bxg7 Kxg7 $19) 27... Bf5 28. Nh2 {wäre dachte ich noch spielbar} Rg6 +29. Re2 Qb4 {ist aber auch traurig und laut dem PC gewonnen}) 27. Qc1 {[%emt 0: +03:50] das Endspiel ist hoffnungslos.} Rg4 {[%emt 0:00:40]} 28. Nc2 {[%emt 0: +00:51]} (28. Bd2 Qb8 29. Nh2 Rg6 {war so traurig, dass ich es gleich verworfen +habe und lieber eine Qualle gegeben habe. Leider muss er sie nicht sofort +nehmen}) 28... Qb6 {[%emt 0:01:06]} 29. Re4 {[%emt 0:00:42]} Bf5 {[%emt 0:00: +08]} 30. Nh2 {[%emt 0:00:06]} Rg6 {[%emt 0:00:57]} 31. Qe1 {[%emt 0:00:46]} Qd8 +{[%emt 0:02:31] der Rest ist eigentlich nicht mehr interessant. Ich glaube +nicht, dass ich danach noch irgendeine Chance habe.} (31... Bxe4 32. Qxe4 { +ist vielleicht noch nicht ganz klar, da der schwarze Turm auf g6 etwas in der +Luft rumhängt.}) 32. b3 {[%emt 0:01:17]} Bxe4 {[%emt 0:01:05]} 33. Qxe4 { +[%emt 0:00:03]} Re6 {[%emt 0:01:13]} 34. Nf3 {[%emt 0:00:18]} Qe8 {[%emt 0:00: +31]} 35. g3 {[%emt 0:01:23]} Qh5 {[%emt 0:01:00]} 36. Re1 {[%emt 0:02:55]} axb3 +{[%emt 0:00:17]} 37. axb3 {[%emt 0:00:04]} Qg4 {[%emt 0:02:41]} 38. Re2 { +[%emt 0:04:05]} Nf6 {[%emt 0:02:39] noch eine schöne letzte ressource.} 39. +Nh2 {[%emt 0:00:38]} Nxe4 {[%emt 0:00:55]} 40. Nxg4 {[%emt 0:00:04]} Nc3 { +[%emt 0:00:11]} 41. Rh2 {[%emt 0:02:24]} Rg6 {[%emt 0:00:10]} 42. Nxh6+ { +[%emt 0:00:15]} Bxh6 {[%emt 0:00:10]} 43. Rxh6 {[%emt 0:00:04]} Ne2+ {[%emt 0: +00:06] Zwei Fehler: 1: Sg5 falsch eingeschätzt. Und 2: hg fg übersehen.} 0-1 + +