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

Manage user stats in score board #146

Merged
merged 9 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
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
2 changes: 1 addition & 1 deletion data/.flutter-plugins-dependencies

Large diffs are not rendered by default.

221 changes: 78 additions & 143 deletions data/lib/api/ball_score/ball_score_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -134,68 +134,6 @@ class FieldingPosition {
});
}

@freezed
class UserStat with _$UserStat {
const factory UserStat({
BattingStat? battingStat,
BowlingStat? bowlingStat,
FieldingStat? fieldingStat,
}) = _UserStat;

factory UserStat.fromJson(Map<String, dynamic> json) =>
_$UserStatFromJson(json);
}

@freezed
class BattingStat with _$BattingStat {
const factory BattingStat({
@Default(0) int innings,
@Default(0) int runScored,
@Default(0.0) double average,
@Default(0.0) double strikeRate,
@Default(0) int ballFaced,
@Default(0) int fours,
@Default(0) int sixes,
@Default(0) int fifties,
@Default(0) int hundreds,
@Default(0) int ducks,
}) = _BattingStat;

factory BattingStat.fromJson(Map<String, dynamic> json) =>
_$BattingStatFromJson(json);
}

@freezed
class BowlingStat with _$BowlingStat {
const factory BowlingStat({
@Default(0) int innings,
@Default(0) int wicketTaken,
@Default(0) int balls,
@Default(0) int runsConceded,
@Default(0) int maiden,
@Default(0) int noBalls,
@Default(0) int wideBalls,
@Default(0.0) double average,
@Default(0.0) double strikeRate,
@Default(0.0) double economyRate,
}) = _BowlingStat;

factory BowlingStat.fromJson(Map<String, dynamic> json) =>
_$BowlingStatFromJson(json);
}

@freezed
class FieldingStat with _$FieldingStat {
const factory FieldingStat({
@Default(0) int catches,
@Default(0) int runOut,
@Default(0) int stumping,
}) = _FieldingStat;

factory FieldingStat.fromJson(Map<String, dynamic> json) =>
_$FieldingStatFromJson(json);
}

@freezed
class OverStatModel with _$OverStatModel {
const factory OverStatModel({
Expand Down Expand Up @@ -698,23 +636,36 @@ extension ExtraSummaryMetaData on ExtraSummary {
}

extension BallScoreList on List<BallScoreModel> {
UserStat calculateUserStats(String currentUserId) {
final battingStat = calculateBattingStats(currentUserId: currentUserId);

final bowlingStat = calculateBowlingStats(currentUserId);

final fieldingStat = calculateFieldingStats(currentUserId);

return UserStat(
battingStat: battingStat,
bowlingStat: bowlingStat,
fieldingStat: fieldingStat,
UserStat calculateUserStats(
String currentUserId, {
UserStat? oldUserStats,
UserStatType? type,
}) {
final newBattingStat = calculateBattingStats(currentUserId);
final newBowlingStat = calculateBowlingStats(currentUserId);
final newFieldingStat = calculateFieldingStats(currentUserId);

final uniqueMatches = where(
(ball) =>
ball.batsman_id == currentUserId ||
ball.non_striker_id == currentUserId ||
ball.bowler_id == currentUserId ||
ball.player_out_id == currentUserId ||
ball.wicket_taker_id == currentUserId,
).map((ball) => ball.match_id).toSet();

final newUserStats = UserStat(
matches: uniqueMatches.length,
type: type,
batting: newBattingStat,
bowling: newBowlingStat,
fielding: newFieldingStat,
);

return oldUserStats?.updateStat(newUserStats) ?? newUserStats;
}

BattingStat calculateBattingStats({
required String currentUserId,
}) {
Batting calculateBattingStats(String currentUserId) {
int runScored = 0;
int dismissal = 0;
int ballFaced = 0;
Expand All @@ -724,60 +675,47 @@ extension BallScoreList on List<BallScoreModel> {
final Map<String, List<BallScoreModel>> inningGroup = {};

for (final element in this) {
// Runs scored
if (element.batsman_id == currentUserId) {
runScored += element.runs_scored;

// Track boundaries
if (element.is_four && element.runs_scored == 4) {
fours++;
} else if (element.is_six && element.runs_scored == 6) {
sixes++;
}

// Count valid balls faced (excluding no balls, wides, etc.)
if (element.extras_type == null ||
element.extras_type == ExtrasType.legBye ||
element.extras_type == ExtrasType.bye) {
ballFaced++;
}
}

// Dismissals
if (element.player_out_id == currentUserId) {
dismissal++;
}

// Group by innings
if (element.batsman_id == currentUserId ||
element.non_striker_id == currentUserId ||
element.player_out_id == currentUserId) {
inningGroup.putIfAbsent(element.inning_id, () => []).add(element);
}
}

// Calculate averages and strike rate
final average = dismissal == 0 ? 0.0 : runScored / dismissal;
final strikeRate = ballFaced == 0 ? 0.0 : (runScored / ballFaced) * 100.0;

// Calculate ducks, fifties, and hundreds
int ducks = 0;
int fifties = 0;
int hundreds = 0;

inningGroup.forEach((inningId, balls) {
int inningRunScored = 0;
int inningBallFaced = 0;
bool isDismissed = false;

for (final ball in balls) {
if (ball.batsman_id == currentUserId) {
inningRunScored += ball.runs_scored;
if (ball.extras_type == null ||
ball.extras_type == ExtrasType.legBye ||
ball.extras_type == ExtrasType.bye) {
inningBallFaced++;
}
}

if (ball.player_out_id == currentUserId &&
Expand All @@ -792,26 +730,27 @@ extension BallScoreList on List<BallScoreModel> {
fifties++;
}

if (isDismissed && inningBallFaced >= 0 && inningBallFaced <= 2) {
if (isDismissed && inningRunScored >= 0 && inningRunScored <= 2) {
cp-mayank marked this conversation as resolved.
Show resolved Hide resolved
ducks++;
}
});

return BattingStat(
return Batting(
innings: inningGroup.length,
average: average,
strikeRate: strikeRate,
ballFaced: ballFaced,
runScored: runScored,
strike_rate: strikeRate,
ball_faced: ballFaced,
run_scored: runScored,
fours: fours,
sixes: sixes,
ducks: ducks,
fifties: fifties,
hundreds: hundreds,
dismissal: dismissal,
);
}

BowlingStat calculateBowlingStats(String currentUserId) {
Bowling calculateBowlingStats(String currentUserId) {
final deliveries = where((element) => element.bowler_id == currentUserId);

final wicketTaken = deliveries
Expand All @@ -827,23 +766,18 @@ extension BallScoreList on List<BallScoreModel> {
final bowledBallCount = deliveries
.where(
(element) =>
element.extras_type != ExtrasType.penaltyRun &&
element.wicket_type != WicketType.retired &&
element.wicket_type != WicketType.retiredHurt &&
element.wicket_type != WicketType.timedOut &&
element.extras_type != ExtrasType.penaltyRun,
element.wicket_type != WicketType.timedOut,
)
.length;

final bowledBallCountForEconomyRate = deliveries
.where(
(element) =>
(element.extras_type == null ||
element.extras_type == ExtrasType.legBye ||
element.extras_type == ExtrasType.bye) &&
element.wicket_type != WicketType.retired &&
element.wicket_type != WicketType.retiredHurt &&
element.wicket_type != WicketType.timedOut &&
element.extras_type != ExtrasType.penaltyRun,
(element) => (element.extras_type == null ||
element.extras_type == ExtrasType.legBye ||
element.extras_type == ExtrasType.bye),
cp-mayank marked this conversation as resolved.
Show resolved Hide resolved
)
.length;

Expand All @@ -856,9 +790,7 @@ extension BallScoreList on List<BallScoreModel> {
);

final average = wicketTaken == 0 ? 0.0 : runsConceded / wicketTaken;

final strikeRate = wicketTaken == 0 ? 0.0 : bowledBallCount / wicketTaken;

final economyRate = bowledBallCountForEconomyRate == 0
? 0.0
: (runsConceded / bowledBallCountForEconomyRate) * 6;
Expand All @@ -869,46 +801,49 @@ extension BallScoreList on List<BallScoreModel> {
final noBallCount = deliveries
.where((element) => element.extras_type == ExtrasType.noBall)
.length;

final inningGroup = groupBy(deliveries, (ball) => ball.inning_id);
final maidenOvers = _calculateMaidenOvers(deliveries);

return Bowling(
innings: inningGroup.length,
average: average,
strike_rate: strikeRate,
wicket_taken: wicketTaken,
economy_rate: economyRate,
balls: bowledBallCount,
wide_balls: wideBallCount,
runs_conceded: runsConceded,
no_balls: noBallCount,
maiden: maidenOvers,
);
}

int _calculateMaidenOvers(Iterable<BallScoreModel> deliveries) {
final overGroups = groupBy(deliveries, (ball) => ball.over_number);

int maiden = 0;

inningGroup.forEach((inningId, balls) {
final overGroup = groupBy(balls, (ball) => ball.over_number);

overGroup.forEach((overNumber, balls) {
int runsConcededInOver = 0;
bool hasExtras = false;

for (final ball in balls) {
runsConcededInOver += ball.runs_scored + (ball.extras_awarded ?? 0);
if (ball.extras_type != null) {
hasExtras = true;
break;
}
cp-mayank marked this conversation as resolved.
Show resolved Hide resolved
}
overGroups.forEach((overNumber, balls) {
int runsConceded = 0;
bool hasExtras = false;

if (runsConcededInOver == 0 && !hasExtras && balls.length == 6) {
maiden++;
for (final ball in balls) {
runsConceded += ball.runs_scored + (ball.extras_awarded ?? 0);
if (ball.extras_type != null) {
hasExtras = true;
break;
}
});
}

if (runsConceded == 0 && !hasExtras && balls.length == 6) {
maiden++;
}
});

return BowlingStat(
innings: inningGroup.length,
average: average,
strikeRate: strikeRate,
wicketTaken: wicketTaken,
economyRate: economyRate,
balls: bowledBallCount,
wideBalls: wideBallCount,
runsConceded: runsConceded,
noBalls: noBallCount,
maiden: maiden,
);
return maiden;
}

FieldingStat calculateFieldingStats(String currentUserId) {
Fielding calculateFieldingStats(String currentUserId) {
final catches = where(
(element) =>
element.wicket_taker_id == currentUserId &&
Expand All @@ -917,22 +852,22 @@ extension BallScoreList on List<BallScoreModel> {
element.wicket_type == WicketType.caughtAndBowled),
).length;

final runOut = where(
final runOuts = where(
(element) =>
element.wicket_taker_id == currentUserId &&
element.wicket_type == WicketType.runOut,
).length;

final stumping = where(
final stumpings = where(
(element) =>
element.wicket_taker_id == currentUserId &&
element.wicket_type == WicketType.stumped,
).length;

return FieldingStat(
return Fielding(
catches: catches,
runOut: runOut,
stumping: stumping,
runOut: runOuts,
stumping: stumpings,
);
}
}
Loading