-
-
Notifications
You must be signed in to change notification settings - Fork 197
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
468 show captured pieces instead of material imbalance #1142
base: main
Are you sure you want to change the base?
Changes from all commits
afd2afc
ae16f79
f467822
7691710
9f528bf
985c69f
c6ff78b
338fda4
f6f7f81
3fe1a77
21fa1e9
c5e81ee
3dfd6b3
913d4a1
b784f93
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,7 @@ class MaterialDiffSide with _$MaterialDiffSide { | |
const factory MaterialDiffSide({ | ||
required IMap<Role, int> pieces, | ||
required int score, | ||
required IMap<Role, int> capturedPieces, | ||
}) = _MaterialDiffSide; | ||
} | ||
|
||
|
@@ -30,11 +31,35 @@ class MaterialDiff with _$MaterialDiff { | |
required MaterialDiffSide white, | ||
}) = _MaterialDiff; | ||
|
||
factory MaterialDiff.fromBoard(Board board) { | ||
factory MaterialDiff.fromBoard(Board board, {Board? startingPosition}) { | ||
int score = 0; | ||
final IMap<Role, int> blackCount = board.materialCount(Side.black); | ||
final IMap<Role, int> whiteCount = board.materialCount(Side.white); | ||
|
||
final IMap<Role, int> blackStartingCount = | ||
startingPosition?.materialCount(Side.black) ?? | ||
Board.standard.materialCount(Side.black); | ||
final IMap<Role, int> whiteStartingCount = | ||
startingPosition?.materialCount(Side.white) ?? | ||
Board.standard.materialCount(Side.white); | ||
|
||
IMap<Role, int> subtractPieceCounts( | ||
IMap<Role, int> startingCount, | ||
IMap<Role, int> subtractCount, | ||
) { | ||
IMap<Role, int> capturedPieces = IMap(); | ||
startingCount.forEach((role, count) { | ||
capturedPieces = | ||
capturedPieces.add(role, count - (subtractCount.get(role) ?? 0)); | ||
}); | ||
return capturedPieces; | ||
} | ||
|
||
final IMap<Role, int> blackCapturedPieces = | ||
subtractPieceCounts(whiteStartingCount, whiteCount); | ||
final IMap<Role, int> whiteCapturedPieces = | ||
subtractPieceCounts(blackStartingCount, blackCount); | ||
|
||
Map<Role, int> count; | ||
Map<Role, int> black; | ||
Map<Role, int> white; | ||
|
@@ -80,8 +105,16 @@ class MaterialDiff with _$MaterialDiff { | |
}); | ||
|
||
return MaterialDiff( | ||
black: MaterialDiffSide(pieces: black.toIMap(), score: -score), | ||
white: MaterialDiffSide(pieces: white.toIMap(), score: score), | ||
black: MaterialDiffSide( | ||
pieces: black.toIMap(), | ||
score: -score, | ||
capturedPieces: blackCapturedPieces, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you extend |
||
), | ||
white: MaterialDiffSide( | ||
pieces: white.toIMap(), | ||
score: score, | ||
capturedPieces: whiteCapturedPieces, | ||
), | ||
); | ||
} | ||
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's some commented-out code here that probably needs to be removed |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -1,4 +1,5 @@ | ||||||
import 'package:chessground/chessground.dart'; | ||||||
import 'package:flutter/material.dart'; | ||||||
import 'package:flutter/widgets.dart'; | ||||||
import 'package:freezed_annotation/freezed_annotation.dart'; | ||||||
import 'package:lichess_mobile/src/model/settings/preferences_storage.dart'; | ||||||
|
@@ -80,9 +81,11 @@ class BoardPreferences extends _$BoardPreferences | |||||
); | ||||||
} | ||||||
|
||||||
Future<void> toggleShowMaterialDifference() { | ||||||
Future<void> setMaterialDifferenceFormat( | ||||||
MaterialDifferenceFormat materialDifferenceFormat, | ||||||
) { | ||||||
return save( | ||||||
state.copyWith(showMaterialDifference: !state.showMaterialDifference), | ||||||
state.copyWith(materialDifferenceFormat: materialDifferenceFormat), | ||||||
); | ||||||
} | ||||||
|
||||||
|
@@ -110,7 +113,7 @@ class BoardPrefs with _$BoardPrefs implements Serializable { | |||||
required bool boardHighlights, | ||||||
required bool coordinates, | ||||||
required bool pieceAnimation, | ||||||
required bool showMaterialDifference, | ||||||
required MaterialDifferenceFormat materialDifferenceFormat, | ||||||
@JsonKey( | ||||||
defaultValue: PieceShiftMethod.either, | ||||||
unknownEnumValue: PieceShiftMethod.either, | ||||||
|
@@ -137,7 +140,7 @@ class BoardPrefs with _$BoardPrefs implements Serializable { | |||||
boardHighlights: true, | ||||||
coordinates: true, | ||||||
pieceAnimation: true, | ||||||
showMaterialDifference: true, | ||||||
materialDifferenceFormat: MaterialDifferenceFormat.materialDifference, | ||||||
pieceShiftMethod: PieceShiftMethod.either, | ||||||
enableShapeDrawings: true, | ||||||
magnifyDraggedPiece: true, | ||||||
|
@@ -300,3 +303,17 @@ enum BoardTheme { | |||||
errorBuilder: (context, o, st) => const SizedBox.shrink(), | ||||||
); | ||||||
} | ||||||
|
||||||
enum MaterialDifferenceFormat { | ||||||
materialDifference(label: 'Material difference'), | ||||||
capturedPieces(label: 'Captured pieces'), | ||||||
hidden(label: 'Hidden'); | ||||||
|
||||||
const MaterialDifferenceFormat({ | ||||||
required this.label, | ||||||
}); | ||||||
|
||||||
final String label; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The label will be translated at some point, so it's maybe better to already make this a method along the lines of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, I am not 100% sure what you mean here (though I understand the broader point). Is there an example somewhere else I could look at? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, I meant something like this:
But actually it's more common in the codebase to do it via a free function, like this:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm yeah I think maybe it sitting in the enum itself makes more sense but I'm not sure. I can implement either approach if there is an opinion either way. For now I might just go with option A, it's easy to change |
||||||
|
||||||
bool get visible => this != MaterialDifferenceFormat.hidden; | ||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,11 +2,13 @@ import 'dart:async'; | |
|
||
import 'package:cached_network_image/cached_network_image.dart'; | ||
import 'package:dartchess/dartchess.dart'; | ||
import 'package:fast_immutable_collections/fast_immutable_collections.dart'; | ||
import 'package:flutter/cupertino.dart'; | ||
import 'package:flutter/material.dart'; | ||
import 'package:lichess_mobile/src/constants.dart'; | ||
import 'package:lichess_mobile/src/model/game/material_diff.dart'; | ||
import 'package:lichess_mobile/src/model/game/player.dart'; | ||
import 'package:lichess_mobile/src/model/settings/board_preferences.dart'; | ||
import 'package:lichess_mobile/src/styles/lichess_colors.dart'; | ||
import 'package:lichess_mobile/src/styles/lichess_icons.dart'; | ||
import 'package:lichess_mobile/src/styles/styles.dart'; | ||
|
@@ -25,6 +27,7 @@ class GamePlayer extends StatelessWidget { | |
required this.player, | ||
this.clock, | ||
this.materialDiff, | ||
this.materialDifferenceFormat, | ||
this.confirmMoveCallbacks, | ||
this.timeToMove, | ||
this.shouldLinkToUserProfile = true, | ||
|
@@ -36,6 +39,7 @@ class GamePlayer extends StatelessWidget { | |
final Player player; | ||
final Widget? clock; | ||
final MaterialDiffSide? materialDiff; | ||
final MaterialDifferenceFormat? materialDifferenceFormat; | ||
|
||
/// if confirm move preference is enabled, used to display confirmation buttons | ||
final ({VoidCallback confirm, VoidCallback cancel})? confirmMoveCallbacks; | ||
|
@@ -140,27 +144,11 @@ class GamePlayer extends StatelessWidget { | |
), | ||
if (timeToMove != null) | ||
MoveExpiration(timeToMove: timeToMove!, mePlaying: mePlaying) | ||
else if (materialDiff != null) | ||
Row( | ||
children: [ | ||
for (final role in Role.values) | ||
for (int i = 0; i < materialDiff!.pieces[role]!; i++) | ||
Icon( | ||
_iconByRole[role], | ||
size: 13, | ||
color: Colors.grey, | ||
), | ||
const SizedBox(width: 3), | ||
Text( | ||
style: const TextStyle( | ||
fontSize: 13, | ||
color: Colors.grey, | ||
), | ||
materialDiff != null && materialDiff!.score > 0 | ||
? '+${materialDiff!.score}' | ||
: '', | ||
), | ||
], | ||
else if (materialDiff != null && | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm wondering if both these conditions should be moved into the new |
||
materialDifferenceFormat?.visible == true) | ||
MaterialDifferenceDisplay( | ||
materialDiff: materialDiff!, | ||
materialDifferenceFormat: materialDifferenceFormat!, | ||
) | ||
else | ||
// to avoid shifts use an empty text widget | ||
|
@@ -325,6 +313,44 @@ class _MoveExpirationState extends State<MoveExpiration> { | |
} | ||
} | ||
|
||
class MaterialDifferenceDisplay extends StatelessWidget { | ||
const MaterialDifferenceDisplay({ | ||
required this.materialDiff, | ||
this.materialDifferenceFormat = MaterialDifferenceFormat.materialDifference, | ||
}); | ||
|
||
final MaterialDiffSide materialDiff; | ||
final MaterialDifferenceFormat materialDifferenceFormat; | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
final IMap<Role, int> piecesToRender = | ||
(materialDifferenceFormat == MaterialDifferenceFormat.capturedPieces | ||
? materialDiff.capturedPieces | ||
: materialDiff.pieces); | ||
|
||
return Row( | ||
children: [ | ||
for (final role in Role.values) | ||
for (int i = 0; i < piecesToRender[role]!; i++) | ||
Icon( | ||
_iconByRole[role], | ||
size: 13, | ||
color: Colors.grey, | ||
), | ||
const SizedBox(width: 3), | ||
Text( | ||
style: const TextStyle( | ||
fontSize: 13, | ||
color: Colors.grey, | ||
), | ||
materialDiff.score > 0 ? '+${materialDiff.score}' : '', | ||
), | ||
], | ||
); | ||
} | ||
} | ||
|
||
const Map<Role, IconData> _iconByRole = { | ||
Role.king: LichessIcons.chess_king, | ||
Role.queen: LichessIcons.chess_queen, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be written in a pure functional way:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I thought this should be possible but I couldn't figure out the right way to do it