Select Git revision
default_game_settings.dart
-
Benoît Harrault authoredBenoît Harrault authored
game_cubit.dart 5.48 KiB
import 'dart:async';
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:hydrated_bloc/hydrated_bloc.dart';
import 'package:awale/models/game/game.dart';
import 'package:awale/models/settings/settings_game.dart';
import 'package:awale/models/settings/settings_global.dart';
import 'package:awale/robot/robot_player.dart';
import 'package:awale/utils/tools.dart';
part 'game_state.dart';
class GameCubit extends HydratedCubit<GameState> {
GameCubit()
: super(GameState(
currentGame: Game.createNull(),
));
void updateState(Game game) {
emit(GameState(
currentGame: game,
));
}
void refresh() {
final Game game = Game(
// Settings
gameSettings: state.currentGame.gameSettings,
globalSettings: state.currentGame.globalSettings,
// State
isRunning: state.currentGame.isRunning,
isStarted: state.currentGame.isStarted,
isFinished: state.currentGame.isFinished,
animationInProgress: state.currentGame.animationInProgress,
// Base data
board: state.currentGame.board,
// Game data
currentPlayer: state.currentGame.currentPlayer,
scores: state.currentGame.scores,
currentHand: state.currentGame.currentHand,
);
// game.dump();
updateState(game);
}
void startNewGame({
required GameSettings gameSettings,
required GlobalSettings globalSettings,
}) {
final Game newGame = Game.createNew(
// Settings
gameSettings: gameSettings,
globalSettings: globalSettings,
);
newGame.dump();
updateState(newGame);
refresh();
robotPlay();
}
void quitGame() {
state.currentGame.isRunning = false;
refresh();
}
void resumeSavedGame() {
state.currentGame.isRunning = true;
refresh();
}
void deleteSavedGame() {
state.currentGame.isRunning = false;
state.currentGame.isFinished = true;
refresh();
}
void toggleCurrentPlayer() {
state.currentGame.currentPlayer = 1 - state.currentGame.currentPlayer;
refresh();
robotPlay();
}
void robotPlay() async {
if (!state.currentGame.isFinished && !state.currentGame.isCurrentPlayerHuman()) {
final int pickedCell = RobotPlayer.pickCell(state.currentGame);
await Future.delayed(const Duration(milliseconds: 500));
tapOnCell(pickedCell);
}
}
void tapOnCell(int cellIndex) async {
printlog('tapOnCell: $cellIndex');
if (!state.currentGame.isCurrentPlayerHouse(cellIndex)) {
printlog('not allowed');
return;
}
if (state.currentGame.board.cells[cellIndex] == 0) {
printlog('empty cell');
return;
}
if (!state.currentGame.isMoveAllowed(cellIndex)) {
printlog('not allowed (need to give at least one seed to other player)');
return;
}
state.currentGame.animationInProgress = true;
refresh();
final int lastCellIndex = await animateSeedsDistribution(cellIndex);
await animateSeedsEarning(lastCellIndex);
toggleCurrentPlayer();
if (!state.currentGame.canPlay()) {
printlog('user has no more move to play');
state.currentGame.isFinished = true;
refresh();
}
state.currentGame.animationInProgress = false;
refresh();
}
Future<int> animateSeedsDistribution(int sourceCellIndex) async {
printlog('animateSeedsDistribution / sourceCellIndex: $sourceCellIndex');
final int seedsCount = state.currentGame.board.cells[sourceCellIndex];
// empty source cell
printlog('animateSeedsDistribution / empty source cell');
state.currentGame.board.cells[sourceCellIndex] = 0;
state.currentGame.currentHand = seedsCount;
refresh();
await Future.delayed(const Duration(milliseconds: 200));
int cellIndex = sourceCellIndex;
for (int i = 0; i < seedsCount; i++) {
cellIndex = state.currentGame.getNextCellIndex(cellIndex, sourceCellIndex);
state.currentGame.currentHand--;
state.currentGame.board.cells[cellIndex] += 1;
refresh();
await Future.delayed(const Duration(milliseconds: 300));
}
refresh();
return cellIndex;
}
Future<int> animateSeedsEarning(int lastCellIndex) async {
printlog('animateSeedsEarning / lastCellIndex: $lastCellIndex');
int earnedSeedsCount = 0;
if (state.currentGame.isOpponentHouse(lastCellIndex)) {
final int seedsCount = state.currentGame.board.cells[lastCellIndex];
printlog('found $seedsCount seed(s) on final house');
if ([2, 3].contains(seedsCount)) {
printlog('-> ok will earn these seeds');
state.currentGame.board.cells[lastCellIndex] = 0;
state.currentGame.scores[state.currentGame.currentPlayer] += seedsCount;
earnedSeedsCount += seedsCount;
refresh();
await Future.delayed(const Duration(milliseconds: 500));
// (recursively) check previous cells
printlog('-> dispatch to previous cell');
final int previousCellIndex = state.currentGame.getPreviousCellIndex(lastCellIndex);
earnedSeedsCount += await animateSeedsEarning(previousCellIndex);
} else {
printlog('-> nothing to do');
}
}
return earnedSeedsCount;
}
@override
GameState? fromJson(Map<String, dynamic> json) {
final Game currentGame = json['currentGame'] as Game;
return GameState(
currentGame: currentGame,
);
}
@override
Map<String, dynamic>? toJson(GameState state) {
return <String, dynamic>{
'currentGame': state.currentGame.toJson(),
};
}
}