Merge pull request #23 from VGVentures/feat/google-letter-mechanic

feat: adding bonus letter feature state management
pull/22/head
Erick 2 years ago committed by GitHub
commit 1af0c2e058
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -9,6 +9,7 @@ class GameBloc extends Bloc<GameEvent, GameState> {
GameBloc() : super(const GameState.initial()) {
on<BallLost>(_onBallLost);
on<Scored>(_onScored);
on<BonusLetterActivated>(_onBonusLetterActivated);
}
void _onBallLost(BallLost event, Emitter emit) {
@ -22,4 +23,15 @@ class GameBloc extends Bloc<GameEvent, GameState> {
emit(state.copyWith(score: state.score + event.points));
}
}
void _onBonusLetterActivated(BonusLetterActivated event, Emitter emit) {
emit(
state.copyWith(
bonusLetters: [
...state.bonusLetters,
event.letter,
],
),
);
}
}

@ -24,3 +24,12 @@ class Scored extends GameEvent {
@override
List<Object?> get props => [points];
}
class BonusLetterActivated extends GameEvent {
const BonusLetterActivated(this.letter);
final String letter;
@override
List<Object?> get props => [letter];
}

@ -8,12 +8,14 @@ class GameState extends Equatable {
const GameState({
required this.score,
required this.balls,
required this.bonusLetters,
}) : assert(score >= 0, "Score can't be negative"),
assert(balls >= 0, "Number of balls can't be negative");
const GameState.initial()
: score = 0,
balls = 3;
balls = 3,
bonusLetters = const [];
/// The current score of the game.
final int score;
@ -23,6 +25,9 @@ class GameState extends Equatable {
/// When the number of balls is 0, the game is over.
final int balls;
/// Active bonus letters.
final List<String> bonusLetters;
/// Determines when the game is over.
bool get isGameOver => balls == 0;
@ -32,6 +37,7 @@ class GameState extends Equatable {
GameState copyWith({
int? score,
int? balls,
List<String>? bonusLetters,
}) {
assert(
score == null || score >= this.score,
@ -41,6 +47,7 @@ class GameState extends Equatable {
return GameState(
score: score ?? this.score,
balls: balls ?? this.balls,
bonusLetters: bonusLetters ?? this.bonusLetters,
);
}
@ -48,5 +55,6 @@ class GameState extends Equatable {
List<Object?> get props => [
score,
balls,
bonusLetters,
];
}

@ -21,9 +21,9 @@ void main() {
}
},
expect: () => [
const GameState(score: 0, balls: 2),
const GameState(score: 0, balls: 1),
const GameState(score: 0, balls: 0),
const GameState(score: 0, balls: 2, bonusLetters: []),
const GameState(score: 0, balls: 1, bonusLetters: []),
const GameState(score: 0, balls: 0, bonusLetters: []),
],
);
});
@ -37,8 +37,8 @@ void main() {
..add(const Scored(points: 2))
..add(const Scored(points: 3)),
expect: () => [
const GameState(score: 2, balls: 3),
const GameState(score: 5, balls: 3),
const GameState(score: 2, balls: 3, bonusLetters: []),
const GameState(score: 5, balls: 3, bonusLetters: []),
],
);
@ -53,9 +53,55 @@ void main() {
bloc.add(const Scored(points: 2));
},
expect: () => [
const GameState(score: 0, balls: 2),
const GameState(score: 0, balls: 1),
const GameState(score: 0, balls: 0),
const GameState(score: 0, balls: 2, bonusLetters: []),
const GameState(score: 0, balls: 1, bonusLetters: []),
const GameState(score: 0, balls: 0, bonusLetters: []),
],
);
});
group('BonusLetterActivated', () {
blocTest<GameBloc, GameState>(
'adds the letter to the state',
build: GameBloc.new,
act: (bloc) => bloc
..add(const BonusLetterActivated('G'))
..add(const BonusLetterActivated('O'))
..add(const BonusLetterActivated('O'))
..add(const BonusLetterActivated('G'))
..add(const BonusLetterActivated('L'))
..add(const BonusLetterActivated('E')),
expect: () => [
const GameState(
score: 0,
balls: 3,
bonusLetters: ['G'],
),
const GameState(
score: 0,
balls: 3,
bonusLetters: ['G', 'O'],
),
const GameState(
score: 0,
balls: 3,
bonusLetters: ['G', 'O', 'O'],
),
const GameState(
score: 0,
balls: 3,
bonusLetters: ['G', 'O', 'O', 'G'],
),
const GameState(
score: 0,
balls: 3,
bonusLetters: ['G', 'O', 'O', 'G', 'L'],
),
const GameState(
score: 0,
balls: 3,
bonusLetters: ['G', 'O', 'O', 'G', 'L', 'E'],
),
],
);
});

@ -40,5 +40,22 @@ void main() {
expect(() => Scored(points: 0), throwsAssertionError);
});
});
group('BonusLetterActivated', () {
test('can be instantiated', () {
expect(const BonusLetterActivated('A'), isNotNull);
});
test('supports value equality', () {
expect(
BonusLetterActivated('A'),
equals(BonusLetterActivated('A')),
);
expect(
BonusLetterActivated('B'),
isNot(equals(BonusLetterActivated('A'))),
);
});
});
});
}

@ -7,14 +7,27 @@ void main() {
group('GameState', () {
test('supports value equality', () {
expect(
GameState(score: 0, balls: 0),
equals(const GameState(score: 0, balls: 0)),
GameState(
score: 0,
balls: 0,
bonusLetters: const [],
),
equals(
const GameState(
score: 0,
balls: 0,
bonusLetters: [],
),
),
);
});
group('constructor', () {
test('can be instantiated', () {
expect(const GameState(score: 0, balls: 0), isNotNull);
expect(
const GameState(score: 0, balls: 0, bonusLetters: []),
isNotNull,
);
});
});
@ -23,7 +36,7 @@ void main() {
'when balls are negative',
() {
expect(
() => GameState(balls: -1, score: 0),
() => GameState(balls: -1, score: 0, bonusLetters: const []),
throwsAssertionError,
);
},
@ -34,7 +47,7 @@ void main() {
'when score is negative',
() {
expect(
() => GameState(balls: 0, score: -1),
() => GameState(balls: 0, score: -1, bonusLetters: const []),
throwsAssertionError,
);
},
@ -47,6 +60,7 @@ void main() {
const gameState = GameState(
balls: 0,
score: 0,
bonusLetters: [],
);
expect(gameState.isGameOver, isTrue);
});
@ -57,6 +71,7 @@ void main() {
const gameState = GameState(
balls: 1,
score: 0,
bonusLetters: [],
);
expect(gameState.isGameOver, isFalse);
});
@ -70,6 +85,7 @@ void main() {
const gameState = GameState(
balls: 1,
score: 0,
bonusLetters: [],
);
expect(gameState.isLastBall, isTrue);
},
@ -82,6 +98,7 @@ void main() {
const gameState = GameState(
balls: 2,
score: 0,
bonusLetters: [],
);
expect(gameState.isLastBall, isFalse);
},
@ -96,6 +113,7 @@ void main() {
const gameState = GameState(
balls: 0,
score: 2,
bonusLetters: [],
);
expect(
() => gameState.copyWith(score: gameState.score - 1),
@ -111,6 +129,7 @@ void main() {
const gameState = GameState(
balls: 0,
score: 2,
bonusLetters: [],
);
expect(
gameState.copyWith(),
@ -126,10 +145,12 @@ void main() {
const gameState = GameState(
score: 2,
balls: 0,
bonusLetters: [],
);
final otherGameState = GameState(
score: gameState.score + 1,
balls: gameState.balls + 1,
bonusLetters: const ['A'],
);
expect(gameState, isNot(equals(otherGameState)));
@ -137,6 +158,7 @@ void main() {
gameState.copyWith(
score: otherGameState.score,
balls: otherGameState.balls,
bonusLetters: otherGameState.bonusLetters,
),
equals(otherGameState),
);

@ -135,7 +135,11 @@ void main() {
whenListen(
gameBloc,
const Stream<GameState>.empty(),
initialState: const GameState(score: 10, balls: 1),
initialState: const GameState(
score: 10,
balls: 1,
bonusLetters: [],
),
);
await game.ready();

@ -67,7 +67,7 @@ void main() {
'renders a game over dialog when the user has lost',
(tester) async {
final gameBloc = MockGameBloc();
const state = GameState(score: 0, balls: 0);
const state = GameState(score: 0, balls: 0, bonusLetters: []);
whenListen(
gameBloc,
Stream.value(state),

Loading…
Cancel
Save