Skip to content

1043 add castling method option v2#1347

Merged
veloce merged 40 commits intolichess-org:mainfrom
Jimima:1043-add-castling-method-option-v2
Apr 1, 2025
Merged

1043 add castling method option v2#1347
veloce merged 40 commits intolichess-org:mainfrom
Jimima:1043-add-castling-method-option-v2

Conversation

@Jimima
Copy link
Copy Markdown
Contributor

@Jimima Jimima commented Jan 8, 2025

Adds an option to change castling method. Still needs some work to tidy up but the approach is implemented. Note that it only really works for Standard variants as chess960 always uses king over rook. I think this is okay but maybe the UI could make this clearer.

@veloce
Copy link
Copy Markdown
Contributor

veloce commented Jan 9, 2025

Just for my understanding, why the v1 was closed? thanks :)

@Jimima
Copy link
Copy Markdown
Contributor Author

Jimima commented Jan 9, 2025

Sure, I had attempted an implementation that modified dartchess and chessground which maybe was not the correct approach. I didn't have a great deal of time to look at it at that point so I just closed the PRs for hygeine. See here for reference lichess-org/dartchess#44

This change is limited to only the mobile app with no changes elsewhere. Not sure if this is the right approach still, happy to be told if you think there is an alternative way to come at it

@Jimima Jimima force-pushed the 1043-add-castling-method-option-v2 branch from c97a375 to b2a2c28 Compare January 17, 2025 10:52
@Jimima Jimima force-pushed the 1043-add-castling-method-option-v2 branch from b2a2c28 to c8348c0 Compare January 17, 2025 10:54
@Jimima Jimima marked this pull request as ready for review January 17, 2025 11:12
@Jimima
Copy link
Copy Markdown
Contributor Author

Jimima commented Jan 17, 2025

I think this is ready to be looked at @veloce. Not sure what's going on with the tests but maybe an issue unrelated to this PR?

@julien4215
Copy link
Copy Markdown
Collaborator

A fix was pushed on the main branch. The tests need to be rerun manually.

@veloce
Copy link
Copy Markdown
Contributor

veloce commented Jan 20, 2025

@Jimima can you rebase your branch on top of main so the tests pass? thank.

@Jimima
Copy link
Copy Markdown
Contributor Author

Jimima commented Jan 20, 2025

@veloce done!

Copy link
Copy Markdown
Contributor

@veloce veloce left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this. This is looking good but there are a couple of issues to address on top of the comments I've made:

  • for now this settings applies only to online games, but it should also apply to puzzles, analysis, study, etc.
  • the logic you added to game_controller.dart must be refactored so it can work everywhere.
  • this is the time for a refactoring: we need a global board wrapper so we can apply settings to the whole app
  • a good starting point for this refactoring imo, is the private _BoardWidget which should be extracted to a public widget in another file. It should be modified to take only BoardPrefs and BoardSettingsOverride (and not directly the ChessboardSettings from chessground which should be constructed inside the widget from the prefs and the optional override).
  • the new castling logic should be tested


// TODO: l10n
String get label => switch (this) {
CastlingMethod.kingOverRook => 'Move king over rook',
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

translation keys already exist: look at app_en.arb: preferencesCastleByMovingOntoTheRook.

PieceShiftMethod.tapTwoSquares => 'Tap two squares',
};

String castlingMethodl10n(BuildContext context, CastlingMethod castlingMethod) =>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicated l10n logic; must be defined directly in the enum to be consistent with rest of code.

@Jimima
Copy link
Copy Markdown
Contributor Author

Jimima commented Jan 21, 2025

Thanks for the feedback, that all makes sense. I also wonder if we are worried about premoves respecting the preference as right now they do not. I think the main site does not either but I would need to check this.

@Jimima Jimima marked this pull request as draft January 21, 2025 09:13
@Jimima
Copy link
Copy Markdown
Contributor Author

Jimima commented Jan 29, 2025

@veloce I would appreciate another review if possible, I have made a few changes:

Created a new BoardWidget component and use this in place of Chessboard where possible
Used translation strings for labels etc.

Some questions:

I wonder if we can support either castling method in the app as it seems like an improvement over the web site. I have left it in for now but can easily remove it if you prefer.

Right now I kept the refactoring light and boardPrefs is passed in as a parameter. Should the board widget be fetching the boardPrefs directly from the shared state rather than taking it as a parameter?

Is there further refactoring to be done? You mentioned taking only BoardPrefs and BoardSettingsOverride but I was a bit unsure about how to make this work. Any further guidance would be gratefully received 🙂

@Jimima Jimima marked this pull request as ready for review January 29, 2025 10:27
@Jimima
Copy link
Copy Markdown
Contributor Author

Jimima commented Jan 29, 2025

Oh yes, also I will add some tests in the meantime

@Jimima
Copy link
Copy Markdown
Contributor Author

Jimima commented Feb 26, 2025

@veloce I had a go at the tests. I can check that clicking on the king highlights the relevant squares as valid moves. I wanted to also test that you could/could not perform a castling move in line with the selected preference. I tried (for way too long) to find a way to make this work but couldn't really figure it out. I think I need to learn a bit more about how everything fits together regarding riverpod, testing, mocking, overrides etc. If you have any guidance here I would appreciate it.

In the process I wondered it in any case the widget should be using the shared state directly rather than being passed in. I think this would simplify mocking the state in the tests but I'm not really sure.

Would really appreciate any guidance you can give me on how to progress this. I also appreciate you are likely very busy so don't feel you need to prioritise responding to me!

@veloce
Copy link
Copy Markdown
Contributor

veloce commented Mar 3, 2025

Will look at it asap @Jimima

required ClockPosition clockPosition,
@JsonKey(defaultValue: PieceShiftMethod.either, unknownEnumValue: PieceShiftMethod.either)
required PieceShiftMethod pieceShiftMethod,
required CastlingMethod castlingMethod,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is required to add a

@JsonKey(defaultValue: CastlingMethod.either, unknownEnumValue: CastlingMethod.either)

otherwise json parsing will fail for people who already save settings.

kingTwoSquares,
either;

String castlingMethodl10n(BuildContext context, CastlingMethod castlingMethod) =>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The preferred way is:

String l10n(AppLocalizations l10n) => switch (this) {
         CastlingMethod.kingOverRook => l10n.preferencesCastleByMovingOntoTheRook,
        CastlingMethod.kingTwoSquares => l10n.preferencesCastleByMovingTwoSquares,
        CastlingMethod.either => 'Either', //TODO l10n string
}

We don't want to pass BuildContext and other enums in the app have the same method named l10n

settingsLabel: Text(
context.l10n.preferencesCastleByMovingTheKingTwoSquaresOrOntoTheRook,
),
settingsValue: boardPrefs.castlingMethod.name,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should use the l10n method of the CastlingMethod enum instead.

return buildScreenRoute(
context,
screen: const CastlingMethodSettingsScreen(),
title: 'Castling method',
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the translated string: preferencesCastleByMovingTheKingTwoSquaresOrOntoTheRook

validMoves: makeLegalMoves(pos),
promotionMove: null,
onMove: (NormalMove move, {bool? isDrop}) {
//This doesn't work because the position is not updated in the UI
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this to work it would need to be part of a StatefulWidget and be called inside setState.

Ideally we'd want to have an higher level test on a whole screen, and that would solve this. This is preferable because if we refactor and remove the InteractiveBoardWidget, the tests for the whole screen will still work and be relevant.

You could for instance test this on the AnalysisScreen, because it is easy to build a test screen with a PGN that gives you a position ready to castle.

You could add a

group('respect castling preferences', () {
   // add your tests here
});

I can take care of the GameScreen tests if you want, since it's a little bit harder to setup (need to mock websocket response). There are already some examples on how to do this though.

@Jimima
Copy link
Copy Markdown
Contributor Author

Jimima commented Mar 14, 2025

Thanks for the review, really helpful comments. I will take a look 👍🏻

@Jimima Jimima force-pushed the 1043-add-castling-method-option-v2 branch from 9c3ed18 to a87e7a0 Compare March 18, 2025 09:45
@Jimima
Copy link
Copy Markdown
Contributor Author

Jimima commented Mar 18, 2025

@veloce I made the requested changes and started to implement the tests on the Analysis screen. I couldn't figure out how to override the preferences, however. I am really not very familiar with this side of things (testing/provider/mocks etc.) so if you can point me in the right direction I would appreciate it. I was trying various things and not really getting very far so thought I would ask to save my sanity, hope you don't mind!

@Jimima
Copy link
Copy Markdown
Contributor Author

Jimima commented Mar 18, 2025

Oh and I don't really know why the checks are failing either 👎🏻

@veloce
Copy link
Copy Markdown
Contributor

veloce commented Mar 24, 2025

@Jimima to override the preferences you have the defaultPreferences parameter of the helper function makeTestProviderScopeApp

Here is an example of its usage for the engine test:

defaultPreferences: {

@Jimima
Copy link
Copy Markdown
Contributor Author

Jimima commented Mar 28, 2025

@veloce added tests on the Analysis screen, please feel free to review when able.


group('Respect castling preference', () {
testWidgets('Castle kingside - king over rook', (tester) async {
final castlingMethodVariantUnderTest = castlingMethodVariant.currentValue!;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test variants are already used to test the different platforms (android, iOS). So here I'd rather use a for loop:

for (final variant in CastlingMethod.values) {
   testWidgets('Castle kingside - king over rook with pref: $variant', (tester) async {
       ...
    }
}

@veloce veloce merged commit 4fefb0e into lichess-org:main Apr 1, 2025
1 check passed
@veloce
Copy link
Copy Markdown
Contributor

veloce commented Apr 1, 2025

Sorry @Jimima I had to refactor, as I didn't want to parse the fen a second time for nothing in InteractiveBoardWidget. And I removed the either option to do the same as website, where kingOverRook acts as either. I also added tests for game screen.

I realise this PR was much harder to do than it was supposed to, because the castling option was not planned from the beginning.

@Jimima
Copy link
Copy Markdown
Contributor Author

Jimima commented Apr 1, 2025

That's cool, I was struggling to find the time to work on it in any case! I'll review what you did just for my learning, thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants