import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; import 'package:hydrated_bloc/hydrated_bloc.dart'; import 'package:jeweled/models/game.dart'; import 'package:jeweled/models/cell_location.dart'; import 'package:jeweled/models/game_settings.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( board: state.currentGame.board, settings: state.currentGame.settings, isRunning: state.currentGame.isRunning, isFinished: state.currentGame.isFinished, availableBlocksCount: state.currentGame.availableBlocksCount, movesCount: state.currentGame.movesCount, score: state.currentGame.score, ); // game.dump(); updateState(game); } void quitGame() { state.currentGame.updateGameIsRunning(false); refresh(); } void updateCellValue(CellLocation locationToUpdate, int? value) { state.currentGame.updateCellValue(locationToUpdate, value); refresh(); } void increaseMovesCount() { this.state.currentGame.increaseMovesCount(); refresh(); } void increaseScore(int increment) { this.state.currentGame.increaseScore(increment); refresh(); } void updateAvailableBlocksCount() { this.state.currentGame.updateAvailableBlocksCount(); refresh(); } void updateGameIsFinished(bool gameIsFinished) { this.state.currentGame.updateGameIsFinished(gameIsFinished); refresh(); } moveCellsDown() { final Game currentGame = this.state.currentGame; final int boardSizeHorizontal = currentGame.settings.boardSize; final int boardSizeVertical = currentGame.settings.boardSize; for (int row = 0; row < boardSizeVertical; row++) { for (int col = 0; col < boardSizeHorizontal; col++) { // empty cell? if (currentGame.getCellValue(CellLocation.go(row, col)) == null) { // move cells down for (int r = row; r > 0; r--) { this.updateCellValue(CellLocation.go(r, col), currentGame.getCellValue(CellLocation.go(r - 1, col))); } // fill top empty cell this.updateCellValue( CellLocation.go(0, col), currentGame.getFillValue(CellLocation.go(row, col))); } } } } void deleteBlock(List<CellLocation> block) { // Sort cells from top to bottom block.sort((cell1, cell2) => cell1.row.compareTo(cell2.row)); // Delete all cells block.forEach((CellLocation blockItemToDelete) { this.updateCellValue(blockItemToDelete, null); }); } int getScoreFromBlock(int blockSize) { return 3 * (blockSize - 2); } List<CellLocation> tapOnCell(CellLocation tappedCellLocation) { final Game currentGame = this.state.currentGame; final int? cellValue = currentGame.getCellValue(tappedCellLocation); if (cellValue != null) { List<CellLocation> blockCells = currentGame.getSiblingCells(tappedCellLocation, []); if (blockCells.length >= 3) { this.deleteBlock(blockCells); this.increaseMovesCount(); this.increaseScore(getScoreFromBlock(blockCells.length)); return blockCells; } } return []; } void postAnimate() { this.moveCellsDown(); this.updateAvailableBlocksCount(); refresh(); if (!this.state.currentGame.hasAtLeastOneAvailableBlock()) { print('no more block found. finish game.'); this.updateGameIsFinished(true); } } void startNewGame(GameSettings settings) { Game newGame = Game.createNew( gameSettings: settings, ); newGame.dump(); updateState(newGame); this.postAnimate(); } @override GameState? fromJson(Map<String, dynamic> json) { Game currentGame = json['currentGame'] as Game; return GameState( currentGame: currentGame, ); } @override Map<String, dynamic>? toJson(GameState state) { return <String, dynamic>{ 'currentGame': state.currentGame.toJson(), }; } }