Created
October 21, 2023 08:56
-
-
Save SerejaSerjik/fce5d1f40ceb82836b4a58aecc0c07c0 to your computer and use it in GitHub Desktop.
Wordle Game Cubit
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import 'dart:async'; | |
| import 'dart:developer' as developer; | |
| import 'dart:math'; | |
| import 'package:equatable/equatable.dart'; | |
| import 'package:hydrated_bloc/hydrated_bloc.dart'; | |
| import 'package:senior_app/core/core.dart'; | |
| import 'package:senior_app/data/data.dart'; | |
| import 'package:senior_app/di/di.dart'; | |
| import 'package:senior_app/domain/domain.dart'; | |
| import 'package:senior_app/utils/utils.dart'; | |
| part 'wordle_game_state.dart'; | |
| class WordleGameCubit extends HydratedCubit<WordleGameState> { | |
| WordleGameCubit({ | |
| required PostWordleAnalyticsEnterToGame postWordleAnalyticsEnterToGame, | |
| required PostWordleAnalyticsGameWin postWordleAnalyticsGameWin, | |
| }) : _postWordleAnalyticsEnterToGame = postWordleAnalyticsEnterToGame, | |
| _postWordleAnalyticsGameWin = postWordleAnalyticsGameWin, | |
| super(WordleGameState.initial()) { | |
| _checkForNewDay(); | |
| _initializeGame(); | |
| _startTimer(); | |
| } | |
| final PostWordleAnalyticsEnterToGame _postWordleAnalyticsEnterToGame; | |
| final PostWordleAnalyticsGameWin _postWordleAnalyticsGameWin; | |
| final StreamController<String> _remainingTimeController = | |
| StreamController<String>.broadcast(); | |
| Stream<String> get remainingTimeStream => _remainingTimeController.stream; | |
| void updateBoardCell(int rowIndex, int colIndex, String value) { | |
| // Creates a new list and also new lists for each inner list | |
| final updatedBoard = | |
| state.board.map((list) => List<String>.from(list)).toList(); | |
| var updatedTryWord = state.currentTryWord; | |
| if (colIndex < 6 && rowIndex <= 5) { | |
| final nextColIndex = colIndex + 1; | |
| updatedBoard[rowIndex][colIndex] = value; | |
| if (state.currentTryWord.length < 5) { | |
| updatedTryWord += value; | |
| } | |
| emit( | |
| state.copyWith( | |
| board: updatedBoard, | |
| currentCol: nextColIndex, | |
| currentRow: rowIndex, | |
| currentTryWord: updatedTryWord, | |
| submittedInvalidWord: false, | |
| ), | |
| ); | |
| } | |
| } | |
| void clearLastEditedCell() { | |
| final updatedBoard = List<List<String>>.from(state.board); | |
| if (state.currentCol >= 1) { | |
| updatedBoard[state.currentRow][state.currentCol - 1] = ''; | |
| emit( | |
| state.copyWith( | |
| board: updatedBoard, | |
| currentCol: state.currentCol - 1, | |
| currentTryWord: state.currentTryWord | |
| .substring(0, state.currentTryWord.length - 1), | |
| submittedInvalidWord: false, | |
| ), | |
| ); | |
| } | |
| } | |
| Future<void> checkWord() async { | |
| final updatedCellStatuses = List<List<CellStatus>>.from(state.cellStatuses); | |
| final updatedBoard = List<List<String>>.from(state.board); | |
| if (state.wordOfTheDay == state.currentTryWord) { | |
| //change status for win, change letters | |
| for (var i = 0; i < state.wordOfTheDay.length; i++) { | |
| updatedCellStatuses[state.currentRow][i] = CellStatus.correctPlace; | |
| } | |
| final updatedCurrentStreak = state.currentStreak + 1; | |
| final updatedGamesPlayed = state.gamesPlayed + 1; | |
| final updatedWinsCount = state.winsCount + 1; | |
| final updatedMaxStreak = updatedCurrentStreak > state.maxStreak | |
| ? updatedCurrentStreak | |
| : state.maxStreak; | |
| sl<PrefManager>().wordleStats = [ | |
| updatedGamesPlayed, | |
| updatedWinsCount, | |
| updatedCurrentStreak, | |
| updatedMaxStreak | |
| ]; | |
| await _postWordleAnalyticsGameWin.call(NoParams()); | |
| emit( | |
| state.copyWith( | |
| gameStatus: WordleGameStatus.won, | |
| cellStatuses: updatedCellStatuses, | |
| board: updatedBoard, | |
| gamesPlayed: updatedGamesPlayed, | |
| winsCount: updatedWinsCount, | |
| currentStreak: updatedCurrentStreak, | |
| maxStreak: updatedMaxStreak, | |
| ), | |
| ); | |
| } else if (state.currentCol == 5 && | |
| !WordleConstants.wordsDict.keys.contains(state.currentTryWord)) { | |
| emit(state.copyWith(submittedInvalidWord: true)); | |
| } else { | |
| // Reset cell statuses for the current row | |
| updatedCellStatuses[state.currentRow] = | |
| List.filled(5, CellStatus.unguessed); | |
| // Compare each letter in the current try word with the word of the day | |
| for (var i = 0; i < state.wordOfTheDay.length; i++) { | |
| if (state.wordOfTheDay[i] == state.currentTryWord[i]) { | |
| updatedCellStatuses[state.currentRow][i] = CellStatus.correctPlace; | |
| } else if (state.wordOfTheDay.contains(state.currentTryWord[i])) { | |
| updatedCellStatuses[state.currentRow][i] = CellStatus.wrongPlace; | |
| } | |
| } | |
| if (state.currentRow == 5 && state.currentCol == 5) { | |
| //check for loss here | |
| const updatedCurrentStreak = 0; | |
| final updatedGamesPlayed = state.gamesPlayed + 1; | |
| final updatedWinsCount = state.winsCount; | |
| final updatedMaxStreak = updatedCurrentStreak > state.maxStreak | |
| ? updatedCurrentStreak | |
| : state.maxStreak; | |
| sl<PrefManager>().wordleStats = [ | |
| updatedGamesPlayed, | |
| updatedWinsCount, | |
| updatedCurrentStreak, | |
| updatedMaxStreak | |
| ]; | |
| emit( | |
| state.copyWith( | |
| board: updatedBoard, | |
| cellStatuses: updatedCellStatuses, | |
| gameStatus: WordleGameStatus.lost, | |
| gamesPlayed: updatedGamesPlayed, | |
| currentStreak: updatedCurrentStreak, | |
| ), | |
| ); | |
| } else { | |
| emit( | |
| state.copyWith( | |
| board: updatedBoard, | |
| cellStatuses: updatedCellStatuses, | |
| currentTryWord: '', | |
| currentRow: state.currentRow + 1, | |
| currentCol: 0, | |
| ), | |
| ); | |
| } | |
| } | |
| } | |
| void showHint() { | |
| emit( | |
| state.copyWith( | |
| showHint: true, | |
| ), | |
| ); | |
| } | |
| void resetGame() { | |
| emit(WordleGameState.initial()); | |
| _generateNewWordOfTheDay(); | |
| checkLetterStatuses( | |
| resetStatus: true, | |
| ); | |
| } | |
| void _startTimer() { | |
| Timer.periodic(const Duration(seconds: 1), (_) { | |
| final remainingTime = _getTimeUntilMidnight(); | |
| _remainingTimeController.add(remainingTime); | |
| }); | |
| } | |
| void _checkForNewDay() { | |
| final now = DateTime.now(); | |
| final lastWordOfTheDayTime = sl<PrefManager>().lastWordOfTheDayTime; | |
| // Uncomment the lines below to check for a new day instead of 2 minutes | |
| // final DateTime currentDay = DateTime(now.year, now.month, now.day); | |
| // final DateTime lastWordOfTheDayDate = DateTime(lastWordOfTheDayTime.year, lastWordOfTheDayTime.month, lastWordOfTheDayTime.day); | |
| // Check if 2 minutes have passed since the last word of the day update | |
| if (now.difference(lastWordOfTheDayTime).inMinutes >= 2) { | |
| // If so, we update the word of the day time to the current time | |
| sl<PrefManager>().lastWordOfTheDayTime = now; | |
| // Then we generate a new word of the day and reset the game | |
| resetGame(); | |
| } | |
| } | |
| void _generateNewWordOfTheDay() { | |
| // Commenting out the old random word logic | |
| // final random = Random(); | |
| // final index = random.nextInt(2152); | |
| // final newWordOfTheDay = WordleConstants.wordsDict.keys.toList()[index]; | |
| // Adding the new logic to always use "vowel" as the word of the day | |
| final newWordOfTheDay = "vowel"; | |
| emit( | |
| state.copyWith( | |
| wordOfTheDay: newWordOfTheDay, | |
| showHint: false, | |
| ), | |
| ); | |
| } | |
| @override | |
| WordleGameState? fromJson(Map<String, dynamic> json) { | |
| return WordleGameState.fromJson(json); | |
| } | |
| @override | |
| Map<String, dynamic>? toJson(WordleGameState state) { | |
| return state.toJson(); | |
| } | |
| Future<void> _initializeGame() async { | |
| await _postWordleAnalyticsEnterToGame.call(NoParams()); | |
| final loadedState = fromJson( | |
| HydratedBloc.storage.read(storageToken) as Map<String, dynamic>? ?? {}, | |
| ); | |
| if (loadedState != null) { | |
| developer.log('state is not null: $loadedState'); | |
| // emit(WordleGameState.initial()); | |
| emit(loadedState); | |
| } else { | |
| emit(WordleGameState.initial()); | |
| } | |
| } | |
| String _getTimeUntilMidnight() { | |
| final now = DateTime.now(); | |
| final midnight = DateTime(now.year, now.month, now.day + 1); | |
| final difference = midnight.difference(now); | |
| return difference.toString().split('.').first.padLeft(8, '0'); | |
| } | |
| void checkLetterStatuses({bool resetStatus = false}) { | |
| final newLetterStatuses = <String, KeyStatus>{}; | |
| final wordOfTheDay = state.wordOfTheDay; | |
| final board = state.board; | |
| for (final letter in WordleConstants.letters) { | |
| if (!wordOfTheDay.contains(letter.toLowerCase())) { | |
| // The letter is not in the word of the day. | |
| newLetterStatuses[letter] = KeyStatus.notInWord; | |
| } else { | |
| // The letter is in the word of the day. | |
| // Let's check if it was guessed. | |
| var guessed = false; | |
| for (final row in board) { | |
| if (row.contains(letter.toLowerCase())) { | |
| guessed = true; | |
| break; | |
| } | |
| } | |
| if (guessed) { | |
| // The letter was guessed. | |
| newLetterStatuses[letter] = KeyStatus.inWord; | |
| } else { | |
| // The letter wasn't guessed. | |
| newLetterStatuses[letter] = KeyStatus.initial; | |
| } | |
| } | |
| } | |
| // At this point, newLetterStatuses contains updated statuses for all the letters. | |
| // Let's update our state. | |
| emit(state.copyWith(lettersStatutes: newLetterStatuses)); | |
| } | |
| } |
In the content marketing world, engaging storytelling is essential. Meta Pixle creates compelling, value-driven content that strengthens brand authority, builds trust, and encourages consistent audience interaction.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This Wordle Game Cubit project is impressive for managing game state and analytics so efficiently. Wordle 6 buchstaben offers a fun twist on classic Wordle puzzles by challenging players with six-letter words, keeping engagement high. The game highlight how structured logic and creativity come together to make word games enjoyable and interactive.