Skip to content
Snippets Groups Projects
Select Git revision
  • 2976e3feddd6b4fca0dc61656196c2e67d977614
  • master default protected
  • 31-upgrade-framework-and-dependencies
  • 12-improve-ai
  • 14-improve-app-metadata
  • Release_0.8.0_25 protected
  • Release_0.7.2_24 protected
  • Release_0.7.1_23 protected
  • Release_0.7.0_22 protected
  • Release_0.6.0_21 protected
  • Release_0.5.0_20 protected
  • Release_0.4.0_19 protected
  • Release_0.3.2_18 protected
  • Release_0.3.1_17 protected
  • Release_0.3.0_16 protected
  • Release_0.2.1_15 protected
  • Release_0.2.0_14 protected
  • Release_0.1.1_13 protected
  • Release_0.1.0_12 protected
  • Release_0.0.11_11 protected
  • Release_0.0.10_10 protected
  • Release_0.0.9_9 protected
  • Release_0.0.8_8 protected
  • Release_0.0.7_7 protected
  • Release_0.0.6_6 protected
25 results

game_cubit.dart

Blame
  • 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(),
        };
      }
    }