From afe893684724dcf53cf56795b0b6aa335055577b Mon Sep 17 00:00:00 2001 From: okmsbun Date: Wed, 14 Feb 2024 10:07:59 +0300 Subject: [PATCH 1/4] alternative rock was forced into normal rock --- lib/src/model/common/node.dart | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/src/model/common/node.dart b/lib/src/model/common/node.dart index d8fd12ff3a..a79f0a525c 100644 --- a/lib/src/model/common/node.dart +++ b/lib/src/model/common/node.dart @@ -192,9 +192,14 @@ abstract class Node { bool prepend = false, }) { final pos = nodeAt(path).position; - final (newPos, newSan) = pos.makeSan(move); + final alternativeCastlingMove = altCastles.containsValue(move.uci) + ? Move.fromUci( + altCastles.entries.firstWhere((e) => e.value == move.uci).key, + ) + : null; + final (newPos, newSan) = pos.makeSan(alternativeCastlingMove ?? move); final newNode = Branch( - sanMove: SanMove(newSan, move), + sanMove: SanMove(newSan, alternativeCastlingMove ?? move), position: newPos, ); return addNodeAt(path, newNode, prepend: prepend); From fe23acf99aad4b919beaa88055cdc0d834fe3cf2 Mon Sep 17 00:00:00 2001 From: okmsbun Date: Wed, 14 Feb 2024 10:10:07 +0300 Subject: [PATCH 2/4] Alternate castling was forced into normal castling --- lib/src/model/common/node.dart | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/src/model/common/node.dart b/lib/src/model/common/node.dart index d8fd12ff3a..a79f0a525c 100644 --- a/lib/src/model/common/node.dart +++ b/lib/src/model/common/node.dart @@ -192,9 +192,14 @@ abstract class Node { bool prepend = false, }) { final pos = nodeAt(path).position; - final (newPos, newSan) = pos.makeSan(move); + final alternativeCastlingMove = altCastles.containsValue(move.uci) + ? Move.fromUci( + altCastles.entries.firstWhere((e) => e.value == move.uci).key, + ) + : null; + final (newPos, newSan) = pos.makeSan(alternativeCastlingMove ?? move); final newNode = Branch( - sanMove: SanMove(newSan, move), + sanMove: SanMove(newSan, alternativeCastlingMove ?? move), position: newPos, ); return addNodeAt(path, newNode, prepend: prepend); From e71ddd99bae0427d7db2cb24a80207c0c403a56c Mon Sep 17 00:00:00 2001 From: okmsbun Date: Tue, 20 Feb 2024 17:43:06 +0300 Subject: [PATCH 3/4] A unit test was written for the method that forces alternative castlings to normal castlings. --- lib/src/model/common/node.dart | 19 +++++++----- test/model/common/node_test.dart | 53 ++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 7 deletions(-) diff --git a/lib/src/model/common/node.dart b/lib/src/model/common/node.dart index a79f0a525c..75c7ed8b93 100644 --- a/lib/src/model/common/node.dart +++ b/lib/src/model/common/node.dart @@ -192,19 +192,24 @@ abstract class Node { bool prepend = false, }) { final pos = nodeAt(path).position; - final alternativeCastlingMove = altCastles.containsValue(move.uci) - ? Move.fromUci( - altCastles.entries.firstWhere((e) => e.value == move.uci).key, - ) - : null; - final (newPos, newSan) = pos.makeSan(alternativeCastlingMove ?? move); + final (newPos, newSan) = pos.makeSan(convertAltCastlingMove(move) ?? move); final newNode = Branch( - sanMove: SanMove(newSan, alternativeCastlingMove ?? move), + sanMove: SanMove(newSan, convertAltCastlingMove(move) ?? move), position: newPos, ); return addNodeAt(path, newNode, prepend: prepend); } + /// The function `convertAltCastlingMove` checks if a move is an alternative + /// castling move and converts it to the corresponding standard castling move if so. + Move? convertAltCastlingMove(Move move) { + return altCastles.containsValue(move.uci) + ? Move.fromUci( + altCastles.entries.firstWhere((e) => e.value == move.uci).key, + ) + : move; + } + /// Deletes the node at the given path. void deleteAt(UciPath path) { parentAt(path).children.removeWhere((child) => child.id == path.last); diff --git a/test/model/common/node_test.dart b/test/model/common/node_test.dart index e06a8340df..4261e32f8d 100644 --- a/test/model/common/node_test.dart +++ b/test/model/common/node_test.dart @@ -453,6 +453,59 @@ void main() { ), ); }); + group('convert alternative castling move', () { + void makeTestAltCastlingMove(String pgn, String alt1, String alt2) { + final root = Root.fromPgnGame(PgnGame.parsePgn(pgn)); + final initialPath = root.mainlinePath; + final initialPng = root.makePgn(); + + final move = Move.fromUci(alt1); + expect(move, isNotNull); + + final newMove = root.convertAltCastlingMove(move!); + expect(newMove, isNotNull); + expect(newMove, Move.fromUci(alt2)); + expect(root.mainline.last.sanMove.move, newMove); + + final previousUciPath = root.mainlinePath.penultimate; + final (newPath, isNewNode) = root.addMoveAt(previousUciPath, move); + expect(newPath, initialPath); + expect(isNewNode, isFalse); + expect(root.makePgn(), initialPng); + } + + test('e1g1 -> e1h1', () { + makeTestAltCastlingMove( + '1. e4 e5 2. Nf3 Nf6 3. Bc4 Bc5 4. O-O', + 'e1g1', + 'e1h1', + ); + }); + + test('e8g8 -> e8h8', () { + makeTestAltCastlingMove( + '1. e4 e5 2. Nf3 Nf6 3. Bc4 Bc5 4. O-O O-O', + 'e8g8', + 'e8h8', + ); + }); + + test('e1c1 -> e1a1', () { + makeTestAltCastlingMove( + '1. d4 d5 2. Nc3 Nc6 3. Be3 Be6 4. Qd3 Qd6 5. O-O-O', + 'e1c1', + 'e1a1', + ); + }); + + test('e8c8 -> e8a8', () { + makeTestAltCastlingMove( + '1. d4 d5 2. Nc3 Nc6 3. Be3 Be6 4. Qd3 Qd6 5. O-O-O O-O-O', + 'e8c8', + 'e8a8', + ); + }); + }); }); } From ae9b770ea2f25a5e388fd348f8c2357b7eb20c17 Mon Sep 17 00:00:00 2001 From: okmsbun Date: Tue, 20 Feb 2024 18:01:15 +0300 Subject: [PATCH 4/4] code review (dart.lineLength) --- lib/src/model/common/node.dart | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/lib/src/model/common/node.dart b/lib/src/model/common/node.dart index d5c3d44473..75c7ed8b93 100644 --- a/lib/src/model/common/node.dart +++ b/lib/src/model/common/node.dart @@ -296,14 +296,18 @@ abstract class Node { while (stack.isNotEmpty) { final frame = stack.removeLast(); - for (int childIdx = 0; childIdx < frame.from.children.length; childIdx++) { + for (int childIdx = 0; + childIdx < frame.from.children.length; + childIdx++) { final childFrom = frame.from.children[childIdx]; final childTo = PgnChildNode( PgnNodeData( san: childFrom.sanMove.san, - startingComments: - childFrom.startingComments?.map((c) => c.makeComment()).toList(), - comments: (childFrom.lichessAnalysisComments ?? childFrom.comments)?.map( + startingComments: childFrom.startingComments + ?.map((c) => c.makeComment()) + .toList(), + comments: + (childFrom.lichessAnalysisComments ?? childFrom.comments)?.map( (c) { final eval = childFrom.eval; final pgnEval = eval?.cp != null @@ -467,7 +471,9 @@ class Root extends Node { while (stack.isNotEmpty) { final frame = stack.removeLast(); - for (int childIdx = 0; childIdx < frame.from.children.length; childIdx++) { + for (int childIdx = 0; + childIdx < frame.from.children.length; + childIdx++) { final childFrom = frame.from.children[childIdx]; final move = frame.to.position.parseSan(childFrom.data.san); if (move != null) { @@ -479,10 +485,13 @@ class Root extends Node { sanMove: SanMove(childFrom.data.san, move), position: newPos, isHidden: hideVariations && childIdx > 0, - lichessAnalysisComments: isLichessAnalysis ? comments?.toList() : null, + lichessAnalysisComments: + isLichessAnalysis ? comments?.toList() : null, startingComments: isLichessAnalysis ? null - : childFrom.data.startingComments?.map(PgnComment.fromPgn).toList(), + : childFrom.data.startingComments + ?.map(PgnComment.fromPgn) + .toList(), comments: isLichessAnalysis ? null : comments?.toList(), nags: childFrom.data.nags, ); @@ -567,21 +576,22 @@ class ViewBranch with _$ViewBranch implements ViewNode { startingComments?.any((c) => c.text?.isNotEmpty == true) == true; /// Has at least one non empty comment text. - bool get hasTextComment => comments?.any((c) => c.text?.isNotEmpty == true) == true; + bool get hasTextComment => + comments?.any((c) => c.text?.isNotEmpty == true) == true; /// Has at least one non empty lichess analysis comment text. bool get hasLichessAnalysisTextComment => lichessAnalysisComments?.any((c) => c.text?.isNotEmpty == true) == true; Duration? get clock { - final clockComment = - (lichessAnalysisComments ?? comments)?.firstWhereOrNull((c) => c.clock != null); + final clockComment = (lichessAnalysisComments ?? comments) + ?.firstWhereOrNull((c) => c.clock != null); return clockComment?.clock; } Duration? get elapsedMoveTime { - final clockComment = - (lichessAnalysisComments ?? comments)?.firstWhereOrNull((c) => c.emt != null); + final clockComment = (lichessAnalysisComments ?? comments) + ?.firstWhereOrNull((c) => c.emt != null); return clockComment?.emt; }