Skip to content

Commit 22a39da

Browse files
authored
More variant support (#2705)
1 parent 9a45217 commit 22a39da

25 files changed

+282
-102
lines changed

ios/Podfile.lock

Lines changed: 48 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -50,61 +50,61 @@ PODS:
5050
- file_picker (0.0.1):
5151
- DKImagePickerController/PhotoGallery
5252
- Flutter
53-
- Firebase/CoreOnly (12.8.0):
54-
- FirebaseCore (~> 12.8.0)
55-
- Firebase/Crashlytics (12.8.0):
53+
- Firebase/CoreOnly (12.9.0):
54+
- FirebaseCore (~> 12.9.0)
55+
- Firebase/Crashlytics (12.9.0):
5656
- Firebase/CoreOnly
57-
- FirebaseCrashlytics (~> 12.8.0)
58-
- Firebase/Messaging (12.8.0):
57+
- FirebaseCrashlytics (~> 12.9.0)
58+
- Firebase/Messaging (12.9.0):
5959
- Firebase/CoreOnly
60-
- FirebaseMessaging (~> 12.8.0)
61-
- firebase_core (4.4.0):
62-
- Firebase/CoreOnly (= 12.8.0)
60+
- FirebaseMessaging (~> 12.9.0)
61+
- firebase_core (4.5.0):
62+
- Firebase/CoreOnly (= 12.9.0)
6363
- Flutter
64-
- firebase_crashlytics (5.0.7):
65-
- Firebase/Crashlytics (= 12.8.0)
64+
- firebase_crashlytics (5.0.8):
65+
- Firebase/Crashlytics (= 12.9.0)
6666
- firebase_core
6767
- Flutter
68-
- firebase_messaging (16.1.1):
69-
- Firebase/Messaging (= 12.8.0)
68+
- firebase_messaging (16.1.2):
69+
- Firebase/Messaging (= 12.9.0)
7070
- firebase_core
7171
- Flutter
72-
- FirebaseCore (12.8.0):
73-
- FirebaseCoreInternal (~> 12.8.0)
72+
- FirebaseCore (12.9.0):
73+
- FirebaseCoreInternal (~> 12.9.0)
7474
- GoogleUtilities/Environment (~> 8.1)
7575
- GoogleUtilities/Logger (~> 8.1)
76-
- FirebaseCoreExtension (12.8.0):
77-
- FirebaseCore (~> 12.8.0)
78-
- FirebaseCoreInternal (12.8.0):
76+
- FirebaseCoreExtension (12.9.0):
77+
- FirebaseCore (~> 12.9.0)
78+
- FirebaseCoreInternal (12.9.0):
7979
- "GoogleUtilities/NSData+zlib (~> 8.1)"
80-
- FirebaseCrashlytics (12.8.0):
81-
- FirebaseCore (~> 12.8.0)
82-
- FirebaseInstallations (~> 12.8.0)
83-
- FirebaseRemoteConfigInterop (~> 12.8.0)
84-
- FirebaseSessions (~> 12.8.0)
80+
- FirebaseCrashlytics (12.9.0):
81+
- FirebaseCore (~> 12.9.0)
82+
- FirebaseInstallations (~> 12.9.0)
83+
- FirebaseRemoteConfigInterop (~> 12.9.0)
84+
- FirebaseSessions (~> 12.9.0)
8585
- GoogleDataTransport (~> 10.1)
8686
- GoogleUtilities/Environment (~> 8.1)
8787
- nanopb (~> 3.30910.0)
8888
- PromisesObjC (~> 2.4)
89-
- FirebaseInstallations (12.8.0):
90-
- FirebaseCore (~> 12.8.0)
89+
- FirebaseInstallations (12.9.0):
90+
- FirebaseCore (~> 12.9.0)
9191
- GoogleUtilities/Environment (~> 8.1)
9292
- GoogleUtilities/UserDefaults (~> 8.1)
9393
- PromisesObjC (~> 2.4)
94-
- FirebaseMessaging (12.8.0):
95-
- FirebaseCore (~> 12.8.0)
96-
- FirebaseInstallations (~> 12.8.0)
94+
- FirebaseMessaging (12.9.0):
95+
- FirebaseCore (~> 12.9.0)
96+
- FirebaseInstallations (~> 12.9.0)
9797
- GoogleDataTransport (~> 10.1)
9898
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
9999
- GoogleUtilities/Environment (~> 8.1)
100100
- GoogleUtilities/Reachability (~> 8.1)
101101
- GoogleUtilities/UserDefaults (~> 8.1)
102102
- nanopb (~> 3.30910.0)
103-
- FirebaseRemoteConfigInterop (12.8.0)
104-
- FirebaseSessions (12.8.0):
105-
- FirebaseCore (~> 12.8.0)
106-
- FirebaseCoreExtension (~> 12.8.0)
107-
- FirebaseInstallations (~> 12.8.0)
103+
- FirebaseRemoteConfigInterop (12.9.0)
104+
- FirebaseSessions (12.9.0):
105+
- FirebaseCore (~> 12.9.0)
106+
- FirebaseCoreExtension (~> 12.9.0)
107+
- FirebaseInstallations (~> 12.9.0)
108108
- GoogleDataTransport (~> 10.1)
109109
- GoogleUtilities/Environment (~> 8.1)
110110
- GoogleUtilities/UserDefaults (~> 8.1)
@@ -170,9 +170,9 @@ PODS:
170170
- Flutter
171171
- receive_sharing_intent (1.8.1):
172172
- Flutter
173-
- SDWebImage (5.21.5):
174-
- SDWebImage/Core (= 5.21.5)
175-
- SDWebImage/Core (5.21.5)
173+
- SDWebImage (5.21.7):
174+
- SDWebImage/Core (= 5.21.7)
175+
- SDWebImage/Core (5.21.7)
176176
- share_plus (0.0.1):
177177
- Flutter
178178
- shared_preferences_foundation (0.0.1):
@@ -306,18 +306,18 @@ SPEC CHECKSUMS:
306306
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
307307
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
308308
file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be
309-
Firebase: 9a58fdbc9d8655ed7b79a19cf9690bb007d3d46d
310-
firebase_core: ee30637e6744af8e0c12a6a1e8a9718506ec2398
311-
firebase_crashlytics: 28b8f39df8104131376393e6af658b8b77dd120f
312-
firebase_messaging: 343de01a8d3e18b60df0c6d37f7174c44ae38e02
313-
FirebaseCore: 0dbad74bda10b8fb9ca34ad8f375fb9dd3ebef7c
314-
FirebaseCoreExtension: 6605938d51f765d8b18bfcafd2085276a252bee2
315-
FirebaseCoreInternal: fe5fa466aeb314787093a7dce9f0beeaad5a2a21
316-
FirebaseCrashlytics: fb31c6907e5b52aa252668394d3f1ab326df1511
317-
FirebaseInstallations: 6a14ab3d694ebd9f839c48d330da5547e9ca9dc0
318-
FirebaseMessaging: 7f42cfd10ec64181db4e01b305a613791c8e782c
319-
FirebaseRemoteConfigInterop: 869ddca16614f979e5c931ece11fbb0b8729ed41
320-
FirebaseSessions: d614ca154c63dbbc6c10d6c38259c2162c4e7c9b
309+
Firebase: 065f2bb395062046623036d8e6dc857bc2521d56
310+
firebase_core: afac1aac13c931e0401c7e74ed1276112030efab
311+
firebase_crashlytics: a316d8dddba772359d93dc38d303ed964579b7a6
312+
firebase_messaging: 7cb2727feb789751fc6936bcc8e08408970e2820
313+
FirebaseCore: 428912f751178b06bef0a1793effeb4a5e09a9b8
314+
FirebaseCoreExtension: e911052d59cd0da237a45d706fc0f81654f035c1
315+
FirebaseCoreInternal: b321eafae5362113bc182956fafc9922cfc77b72
316+
FirebaseCrashlytics: 43913d587ef07beaf5db703baa61eacf9554658c
317+
FirebaseInstallations: 7b64ffd006032b2b019a59b803858df5112d9eaa
318+
FirebaseMessaging: 7d6cdbff969127c4151c824fe432f0e301210f15
319+
FirebaseRemoteConfigInterop: 765ee19cd2bfa8e54937c8dae901eb634ad6787d
320+
FirebaseSessions: a2d06fd980431fda934c7a543901aca05fc4edcc
321321
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
322322
flutter_appauth: d4abcf54856e5d8ba82ed7646ffc83245d4aa448
323323
flutter_local_notifications: a5a732f069baa862e728d839dd2ebb904737effb
@@ -335,7 +335,7 @@ SPEC CHECKSUMS:
335335
PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851
336336
quick_actions_ios: 500fcc11711d9f646739093395c4ae8eec25f779
337337
receive_sharing_intent: 222384f00ffe7e952bbfabaa9e3967cb87e5fe00
338-
SDWebImage: e9c98383c7572d713c1a0d7dd2783b10599b9838
338+
SDWebImage: e9fc87c1aab89a8ab1bbd74eba378c6f53be8abf
339339
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
340340
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
341341
sound_effect: fa0600cdb9ebdc8ca14671fdc20418d7c223e92b

lib/src/model/analysis/analysis_controller.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -861,10 +861,13 @@ class AnalysisController extends AsyncNotifier<AnalysisState>
861861

862862
@freezed
863863
sealed class AnalysisState
864-
with _$AnalysisState
864+
with _$AnalysisState, AnalysisExplosionMixin
865865
implements EvaluationMixinState, CommonAnalysisState {
866866
const AnalysisState._();
867867

868+
@override
869+
ViewRoot get analysisRoot => root;
870+
868871
const factory AnalysisState({
869872
/// The ID of the game if it's a lichess game.
870873
required GameId? gameId,

lib/src/model/analysis/common_analysis_state.dart

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
import 'package:collection/collection.dart';
12
import 'package:dartchess/dartchess.dart';
23
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
34
import 'package:lichess_mobile/src/model/common/chess.dart';
45
import 'package:lichess_mobile/src/model/common/eval.dart';
6+
import 'package:lichess_mobile/src/model/common/node.dart';
7+
import 'package:lichess_mobile/src/model/common/uci.dart';
58
import 'package:lichess_mobile/src/model/engine/evaluation_preferences.dart';
69

710
/// Interface for Analysis's State.
@@ -29,6 +32,40 @@ abstract class CommonAnalysisState {
2932

3033
/// Possible promotion move to be played.
3134
NormalMove? get promotionMove;
35+
36+
/// Squares that should have an atomic explosion animation after the last move.
37+
///
38+
/// Returns `null` if the variant is not atomic, there is no last move, or the
39+
/// last move was not a capture (no explosion occurs).
40+
ISet<Square>? get explosionSquares;
41+
}
42+
43+
/// Mixin that computes [CommonAnalysisState.explosionSquares] for states that
44+
/// have a position tree ([ViewRoot]) and a current path ([UciPath]).
45+
///
46+
/// The mixin walks up one step in the tree to find the position **before** the
47+
/// last move, then delegates to dartchess's [Atomic.explosionSquares].
48+
mixin AnalysisExplosionMixin implements CommonAnalysisState {
49+
/// The tree root used to find the parent position.
50+
///
51+
/// Return `null` if the tree is not available (e.g. illegal starting
52+
/// position), in which case no explosion will be shown.
53+
ViewRoot? get analysisRoot;
54+
55+
/// The path of the current node inside [analysisRoot].
56+
UciPath get currentPath;
57+
58+
@override
59+
ISet<Square>? get explosionSquares {
60+
if (variant != Variant.atomic || lastMove == null || currentPath.isEmpty) return null;
61+
final root = analysisRoot;
62+
if (root == null) return null;
63+
final parentPos =
64+
root.branchesOn(currentPath.penultimate).lastOrNull?.position ?? root.position;
65+
if (parentPos is! Atomic) return null;
66+
final squareSet = parentPos.explosionSquares(lastMove!);
67+
return squareSet.isEmpty ? null : squareSet.squares.toISet();
68+
}
3269
}
3370

3471
/// Interface for Analysis's current node.

lib/src/model/analysis/retro_controller.dart

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ class RetroController extends AsyncNotifier<RetroState> with EngineEvaluationMix
138138
currentNode: RetroCurrentNode.fromNode(_root),
139139
variant: _game.meta.variant,
140140
currentPath: UciPath.empty,
141+
root: _root.view,
141142
evaluationContext: EvaluationContext(
142143
id: options.id,
143144
variant: _game.meta.variant,
@@ -229,6 +230,7 @@ class RetroController extends AsyncNotifier<RetroState> with EngineEvaluationMix
229230
currentNode: RetroCurrentNode.fromNode(mistakes.firstOrNull?.branch.branch ?? _root),
230231
lastMove: mistakes.firstOrNull?.branch.sanMove.move,
231232
variant: _game.meta.variant,
233+
root: _root.view,
232234
evaluationContext: EvaluationContext(
233235
id: options.id,
234236
variant: _game.meta.variant,
@@ -370,6 +372,7 @@ class RetroController extends AsyncNotifier<RetroState> with EngineEvaluationMix
370372
currentNode: RetroCurrentNode.fromNode(currentNode),
371373
lastMove: currentNode.sanMove.move,
372374
promotionMove: null,
375+
root: isNavigating ? state.root : _root.view,
373376
),
374377
);
375378
} else {
@@ -379,6 +382,7 @@ class RetroController extends AsyncNotifier<RetroState> with EngineEvaluationMix
379382
currentNode: RetroCurrentNode.fromNode(currentNode),
380383
lastMove: null,
381384
promotionMove: null,
385+
root: isNavigating ? state.root : _root.view,
382386
),
383387
);
384388
}
@@ -485,7 +489,9 @@ class RetroController extends AsyncNotifier<RetroState> with EngineEvaluationMix
485489
enum RetroFeedback { findMove, evalMove, correct, incorrect, viewingSolution, done }
486490

487491
@freezed
488-
sealed class RetroState with _$RetroState implements EvaluationMixinState, CommonAnalysisState {
492+
sealed class RetroState
493+
with _$RetroState, AnalysisExplosionMixin
494+
implements EvaluationMixinState, CommonAnalysisState {
489495
const RetroState._();
490496

491497
const factory RetroState({
@@ -502,6 +508,7 @@ sealed class RetroState with _$RetroState implements EvaluationMixinState, Commo
502508
required Variant variant,
503509
required UciPath currentPath,
504510
required EvaluationContext evaluationContext,
511+
required ViewRoot root,
505512
DateTime? evalRequestedAt,
506513
Move? lastMove,
507514
NormalMove? promotionMove,
@@ -526,6 +533,9 @@ sealed class RetroState with _$RetroState implements EvaluationMixinState, Commo
526533
@override
527534
Position get currentPosition => currentNode.position;
528535

536+
@override
537+
ViewRoot get analysisRoot => root;
538+
529539
@override
530540
bool isEngineAvailable(EngineEvaluationPrefState prefs) => true;
531541

lib/src/model/broadcast/broadcast_analysis_controller.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -556,10 +556,13 @@ class BroadcastAnalysisController extends AsyncNotifier<BroadcastAnalysisState>
556556

557557
@freezed
558558
sealed class BroadcastAnalysisState
559-
with _$BroadcastAnalysisState
559+
with _$BroadcastAnalysisState, AnalysisExplosionMixin
560560
implements EvaluationMixinState, CommonAnalysisState {
561561
const BroadcastAnalysisState._();
562562

563+
@override
564+
ViewRoot get analysisRoot => root;
565+
563566
const factory BroadcastAnalysisState({
564567
/// Broadcast game ID
565568
required StringId id,

lib/src/model/common/chess.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ const ISet<Variant> readSupportedVariants = ISetConst({
9090
Variant.chess960,
9191
Variant.fromPosition,
9292
Variant.antichess,
93+
Variant.atomic,
9394
Variant.kingOfTheHill,
9495
Variant.threeCheck,
9596
Variant.racingKings,
@@ -102,6 +103,13 @@ const ISet<Variant> playSupportedVariants = ISetConst({
102103
Variant.standard,
103104
Variant.chess960,
104105
Variant.fromPosition,
106+
Variant.antichess,
107+
Variant.atomic,
108+
Variant.kingOfTheHill,
109+
Variant.threeCheck,
110+
Variant.racingKings,
111+
Variant.horde,
112+
Variant.crazyhouse,
105113
});
106114

107115
enum Variant {

0 commit comments

Comments
 (0)