Skip to content
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

Open
wants to merge 29 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
afd2afc
WIP
Jimima Nov 8, 2024
ae16f79
WIP
Jimima Nov 8, 2024
f467822
Format fix
Jimima Nov 8, 2024
7691710
WIP with settings option
Jimima Nov 11, 2024
9f528bf
Version with single option with 3 choices
Jimima Nov 12, 2024
985c69f
Added in-game preference option
Jimima Nov 14, 2024
c6ff78b
Fix format
Jimima Nov 14, 2024
338fda4
Merge branch 'main' into 468-show-captured-pieces-instead-of-material…
Jimima Nov 14, 2024
f6f7f81
Removed comments
Jimima Nov 15, 2024
3fe1a77
Refactored enum
Jimima Nov 15, 2024
21fa1e9
Added test for captured pieces
Jimima Nov 15, 2024
c5e81ee
Format
Jimima Nov 15, 2024
3dfd6b3
Parameterised starting position
Jimima Nov 15, 2024
913d4a1
Refactor
Jimima Nov 15, 2024
b784f93
Removed comment
Jimima Nov 15, 2024
46a7480
Placeholder l10n implementation
Jimima Nov 16, 2024
b8e7a04
Refactor
Jimima Nov 20, 2024
a4716f7
Syntax fix(?)
Jimima Nov 20, 2024
13e003d
Merge branch 'main' into 468-show-captured-pieces-instead-of-material…
Jimima Nov 20, 2024
66d561a
Merge fix
Jimima Nov 20, 2024
c3f98e2
Refactor
Jimima Nov 20, 2024
b6d4599
Modified null handling
Jimima Nov 20, 2024
18297ce
Removed duplicates from board settings page
Jimima Nov 20, 2024
9a84086
Removed from game settings (also duplicates)
Jimima Nov 20, 2024
3815037
Appeased linter
Jimima Nov 20, 2024
556a374
Merge branch 'main' into 468-show-captured-pieces-instead-of-material…
Jimima Nov 20, 2024
5a6db91
Added alternate picker on ios
Jimima Nov 21, 2024
daf377a
Merge branch '468-show-captured-pieces-instead-of-material-imbalance'…
Jimima Nov 21, 2024
442a4fd
Linter fix
Jimima Nov 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 33 additions & 3 deletions lib/src/model/game/material_diff.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -30,11 +31,32 @@ 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,
) {
return startingCount.map(
(role, count) => MapEntry(role, count - (subtractCount.get(role) ?? 0)),
);
}

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;
Expand Down Expand Up @@ -80,8 +102,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,
Jimima marked this conversation as resolved.
Show resolved Hide resolved
),
white: MaterialDiffSide(
pieces: white.toIMap(),
score: score,
capturedPieces: whiteCapturedPieces,
),
);
}

Expand Down
33 changes: 29 additions & 4 deletions lib/src/model/settings/board_preferences.dart
Jimima marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
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/l10n/l10n.dart';
import 'package:lichess_mobile/src/model/settings/preferences_storage.dart';
import 'package:lichess_mobile/src/styles/styles.dart';
import 'package:lichess_mobile/src/utils/color_palette.dart';
Expand Down Expand Up @@ -84,9 +86,11 @@ class BoardPreferences extends _$BoardPreferences
return save(state.copyWith(dragTargetKind: dragTargetKind));
}

Future<void> toggleShowMaterialDifference() {
Future<void> setMaterialDifferenceFormat(
MaterialDifferenceFormat materialDifferenceFormat,
) {
return save(
state.copyWith(showMaterialDifference: !state.showMaterialDifference),
state.copyWith(materialDifferenceFormat: materialDifferenceFormat),
);
}

Expand Down Expand Up @@ -120,7 +124,7 @@ class BoardPrefs with _$BoardPrefs implements Serializable {
required bool boardHighlights,
required bool coordinates,
required bool pieceAnimation,
required bool showMaterialDifference,
required MaterialDifferenceFormat materialDifferenceFormat,
required ClockPosition clockPosition,
@JsonKey(
defaultValue: PieceShiftMethod.either,
Expand Down Expand Up @@ -150,7 +154,7 @@ class BoardPrefs with _$BoardPrefs implements Serializable {
boardHighlights: true,
coordinates: true,
pieceAnimation: true,
showMaterialDifference: true,
materialDifferenceFormat: MaterialDifferenceFormat.materialDifference,
clockPosition: ClockPosition.right,
pieceShiftMethod: PieceShiftMethod.either,
enableShapeDrawings: true,
Expand Down Expand Up @@ -317,6 +321,27 @@ enum BoardTheme {
);
}

enum MaterialDifferenceFormat {
materialDifference(label: 'Material difference'),
capturedPieces(label: 'Captured pieces'),
hidden(label: 'Hidden');

const MaterialDifferenceFormat({
required this.label,
});

final String label;
Jimima marked this conversation as resolved.
Show resolved Hide resolved

bool get visible => this != MaterialDifferenceFormat.hidden;

String l10n(AppLocalizations l10n) => switch (this) {
//TODO: Add l10n
MaterialDifferenceFormat.materialDifference => materialDifference.label,
MaterialDifferenceFormat.capturedPieces => capturedPieces.label,
MaterialDifferenceFormat.hidden => hidden.label,
};
}

enum ClockPosition {
left,
right;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,9 @@ class _BodyState extends ConsumerState<_Body> {

@override
Widget build(BuildContext context) {
final shouldShowMaterialDiff = ref.watch(
final materialDifference = ref.watch(
boardPreferencesProvider.select(
(prefs) => prefs.showMaterialDifference,
(prefs) => prefs.materialDifferenceFormat,
),
);

Expand All @@ -157,9 +157,10 @@ class _BodyState extends ConsumerState<_Body> {

final black = GamePlayer(
player: game.black,
materialDiff: shouldShowMaterialDiff
materialDiff: materialDifference.visible
? game.materialDiffAt(stepCursor, Side.black)
: null,
materialDifferenceFormat: materialDifference,
shouldLinkToUserProfile: false,
mePlaying: youAre == Side.black,
confirmMoveCallbacks: youAre == Side.black && moveToConfirm != null
Expand All @@ -179,9 +180,10 @@ class _BodyState extends ConsumerState<_Body> {
);
final white = GamePlayer(
player: game.white,
materialDiff: shouldShowMaterialDiff
materialDiff: materialDifference.visible
? game.materialDiffAt(stepCursor, Side.white)
: null,
materialDifferenceFormat: materialDifference,
shouldLinkToUserProfile: false,
mePlaying: youAre == Side.white,
confirmMoveCallbacks: youAre == Side.white && moveToConfirm != null
Expand Down
6 changes: 4 additions & 2 deletions lib/src/view/game/game_body.dart
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,10 @@ class GameBody extends ConsumerWidget {

final black = GamePlayer(
player: gameState.game.black,
materialDiff: boardPreferences.showMaterialDifference
materialDiff: boardPreferences.materialDifferenceFormat.visible
? gameState.game.materialDiffAt(gameState.stepCursor, Side.black)
: null,
materialDifferenceFormat: boardPreferences.materialDifferenceFormat,
timeToMove: gameState.game.sideToMove == Side.black
? gameState.timeToMove
: null,
Expand Down Expand Up @@ -174,9 +175,10 @@ class GameBody extends ConsumerWidget {
);
final white = GamePlayer(
player: gameState.game.white,
materialDiff: boardPreferences.showMaterialDifference
materialDiff: boardPreferences.materialDifferenceFormat.visible
? gameState.game.materialDiffAt(gameState.stepCursor, Side.white)
: null,
materialDifferenceFormat: boardPreferences.materialDifferenceFormat,
timeToMove: gameState.game.sideToMove == Side.white
? gameState.timeToMove
: null,
Expand Down
76 changes: 49 additions & 27 deletions lib/src/view/game/game_player.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ 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:flutter_riverpod/flutter_riverpod.dart';
Expand All @@ -28,6 +29,7 @@ class GamePlayer extends StatelessWidget {
required this.player,
this.clock,
this.materialDiff,
this.materialDifferenceFormat,
this.confirmMoveCallbacks,
this.timeToMove,
this.shouldLinkToUserProfile = true,
Expand All @@ -40,6 +42,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;
Expand Down Expand Up @@ -148,33 +151,12 @@ class GamePlayer extends StatelessWidget {
if (timeToMove != null)
MoveExpiration(timeToMove: timeToMove!, mePlaying: mePlaying)
else if (materialDiff != null)
Row(
mainAxisAlignment: clockPosition == ClockPosition.right
? MainAxisAlignment.start
: MainAxisAlignment.end,
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
// to avoid shifts use an empty text widget
const Text('', style: TextStyle(fontSize: 13)),
MaterialDifferenceDisplay(
materialDiff: materialDiff!,
materialDifferenceFormat: materialDifferenceFormat,
),
// to avoid shifts use an empty text widget
const Text('', style: TextStyle(fontSize: 13)),
],
);

Expand Down Expand Up @@ -347,6 +329,46 @@ class _MoveExpirationState extends ConsumerState<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 materialDifferenceFormat?.visible ?? true
? 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 SizedBox.shrink();
}
}

const Map<Role, IconData> _iconByRole = {
Role.king: LichessIcons.chess_king,
Role.queen: LichessIcons.chess_queen,
Expand Down
1 change: 0 additions & 1 deletion lib/src/view/game/game_settings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import 'package:lichess_mobile/src/view/settings/board_settings_screen.dart';
import 'package:lichess_mobile/src/widgets/adaptive_bottom_sheet.dart';
import 'package:lichess_mobile/src/widgets/list.dart';
import 'package:lichess_mobile/src/widgets/settings.dart';

import 'game_screen_providers.dart';

class GameSettings extends ConsumerWidget {
Expand Down
3 changes: 2 additions & 1 deletion lib/src/view/over_the_board/over_the_board_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -301,9 +301,10 @@ class _Player extends ConsumerWidget {
name: side.name.capitalize(),
),
),
materialDiff: boardPreferences.showMaterialDifference
materialDiff: boardPreferences.materialDifferenceFormat.visible
? gameState.currentMaterialDiff(side)
: null,
materialDifferenceFormat: boardPreferences.materialDifferenceFormat,
shouldLinkToUserProfile: false,
clock: clock.timeIncrement.isInfinite
? null
Expand Down
Loading