diff --git a/packages/trashy_road/lib/src/maps/bloc/game_maps_state.dart b/packages/trashy_road/lib/src/maps/bloc/game_maps_state.dart index 8281d23b..467af101 100644 --- a/packages/trashy_road/lib/src/maps/bloc/game_maps_state.dart +++ b/packages/trashy_road/lib/src/maps/bloc/game_maps_state.dart @@ -6,6 +6,21 @@ part of 'game_maps_bloc.dart'; /// [GameMap] itself. typedef GameMapsCollection = UnmodifiableMapView; +/// {@template RatingSteps} +/// The steps that dictate the rating of the map score. +/// +/// It expects three integers, where the first index is the minimum score +/// (inclusive) required to achieve a bronze rating, the second index is the +/// minimum score (inclusive) required to achieve a silver rating, and the third +/// index is the minimum score (inclusive) required to achieve a gold rating. +/// +/// For example, if the player completes the map in 75 steps, and the score +/// steps are [100, 50, 25], then the player will achieve a bronze score. +/// Whereas if the player completes the map in 25 steps, then the player will +/// achieve a gold score. +/// {@endtemplate} +typedef RatingSteps = (int, int, int); + class GameMapsState extends Equatable { GameMapsState({ required Map maps, @@ -18,12 +33,14 @@ class GameMapsState extends Equatable { identifier: 'map1', path: Assets.tiles.map1, score: 0, + ratingSteps: (100, 50, 25), locked: false, ), 'map2': GameMap._( identifier: 'map2', path: Assets.tiles.map2, score: 0, + ratingSteps: (100, 50, 25), locked: true, ), }, @@ -55,6 +72,38 @@ class GameMapsState extends Equatable { List get props => [maps]; } +/// {@template ScoreRating} +/// The rating of a score. +/// +/// See also: +/// +/// * [RatingSteps] for the steps that dictate the rating of the map score. +/// {@endtemplate} +enum ScoreRating { + none._(value: 0), + bronze._(value: 1), + silver._(value: 2), + gold._(value: 3); + + const ScoreRating._({required this.value}); + + /// Creates a [ScoreRating] from the given [RatingSteps] and [score]. + factory ScoreRating.fromSteps({ + required int score, + required RatingSteps steps, + }) { + if (score >= steps.$3) return gold; + if (score >= steps.$2) return silver; + if (score >= steps.$1) return bronze; + return none; + } + + /// The value of the score. + /// + /// The higher the value, the better the rating. + final int value; +} + /// {@template GameMapMetadata} /// Stores the metadata of a map game. /// @@ -63,12 +112,16 @@ class GameMapsState extends Equatable { /// provided by the `PreloadCubit`. /// {@endtemplate} class GameMap extends Equatable { - const GameMap._({ + GameMap._({ required this.identifier, required this.score, + required this.ratingSteps, required this.locked, required this.path, - }); + }) : scoreRating = ScoreRating.fromSteps( + score: score, + steps: ratingSteps, + ); /// The identifier of the map. final String identifier; @@ -78,6 +131,12 @@ class GameMap extends Equatable { /// A score of 0 means the map has not been played yet. final int score; + /// {@macro RatingSteps} + final RatingSteps ratingSteps; + + /// {@macro ScoreRating} + final ScoreRating scoreRating; + /// Whether the map is locked and cannot be played. /// /// A locked map is usually a map that is not yet available to the player. @@ -89,17 +148,26 @@ class GameMap extends Equatable { GameMap copyWith({ String? identifier, int? score, + RatingSteps? ratingSteps, bool? locked, String? path, }) { return GameMap._( identifier: identifier ?? this.identifier, score: score ?? this.score, + ratingSteps: ratingSteps ?? this.ratingSteps, locked: locked ?? this.locked, path: path ?? this.path, ); } @override - List get props => [identifier, score, locked, path]; + List get props => [ + identifier, + score, + ratingSteps, + scoreRating, + locked, + path, + ]; } diff --git a/packages/trashy_road/test/src/maps/bloc/game_maps_state_test.dart b/packages/trashy_road/test/src/maps/bloc/game_maps_state_test.dart new file mode 100644 index 00000000..6ca2e7db --- /dev/null +++ b/packages/trashy_road/test/src/maps/bloc/game_maps_state_test.dart @@ -0,0 +1,42 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:trashy_road/src/maps/maps.dart'; + +void main() { + group('$ScoreRating', () { + group('fromSteps', () { + test( + 'returns ScoreRating.none when score is less than the first step', + () { + final rating = ScoreRating.fromSteps(score: 0, steps: (1, 2, 3)); + expect(rating, ScoreRating.none); + }, + ); + + test( + '''returns ScoreRating.bronze when score is greater or equal than the first step ''' + 'and less than the second step', + () { + final rating = ScoreRating.fromSteps(score: 1, steps: (1, 2, 3)); + expect(rating, ScoreRating.bronze); + }, + ); + + test( + '''returns ScoreRating.silver when score is greater or equal than the second step ''' + 'and less than the third step', + () { + final rating = ScoreRating.fromSteps(score: 2, steps: (1, 2, 3)); + expect(rating, ScoreRating.silver); + }, + ); + + test( + '''returns ScoreRating.gold when score is greater or equal than the third step''', + () { + final rating = ScoreRating.fromSteps(score: 3, steps: (1, 2, 3)); + expect(rating, ScoreRating.gold); + }, + ); + }); + }); +}