Skip to content

Commit

Permalink
Game: Add game logic classes
Browse files Browse the repository at this point in the history
  • Loading branch information
Poldraunic committed Jan 2, 2024
1 parent 24bc89c commit 0cc9e19
Show file tree
Hide file tree
Showing 7 changed files with 13,687 additions and 0 deletions.
30 changes: 30 additions & 0 deletions .metadata
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.

version:
revision: "78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9"
channel: "stable"

project_type: app

# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
- platform: windows
create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9

# User provided section

# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'
4 changes: 4 additions & 0 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
include: package:flutter_lints/flutter.yaml

linter:
rules:
179 changes: 179 additions & 0 deletions lib/game/game.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
import 'dart:math' as math;

import 'package:characters/characters.dart';
import 'package:flutter/foundation.dart';
import 'package:wordle/game/letter.dart';
import 'package:wordle/game/words.dart';

typedef WordMatchResult = List<Letter>;

enum SubmitResult {
notEnoughLetters,
noSuchWord,
incorrectWord,
lose,
win,
}

class Game extends ChangeNotifier {
late int _attempts;
late int _currentAttempt;
late String _secretWord;
late List<WordMatchResult> _guesses;
late String _currentWord;
late Map<String, LetterMatch> _usedLetters;
bool _finished = false;

int get attempts => _attempts;

int get currentAttempt => _currentAttempt;

String get currentWord => _currentWord;

Game() {
restart();
_randomizeSecretWord();
}

Game.withSecretWord(String secretWord) {
restart();
_setSecretWord(secretWord);
}

Letter letterAt(int i, int j) {
if (i == _currentAttempt - 1) {
String? character = _currentWord.characters.elementAtOrNull(j);
return character == null ? const Letter.empty() : Letter.unmatched(character);
}

return _guesses.elementAtOrNull(i)?.elementAt(j) ?? const Letter.empty();
}

LetterMatch? matchForLetter(String letter) {
return _usedLetters[letter];
}

void pushLetter(String letter) {
if (_finished) {
return;
}

if (_currentWord.length == 5) {
print("letter limit reached");
return;
}

assert(letter.isNotEmpty);
assert(letter.length == 1);
assert(letter.contains(RegExp("\\w")));

_currentWord += letter.toUpperCase();

print("push: $letter");
notifyListeners();
}

void pushLetters(String letters) {
if (_finished) {
return;
}

for (var letter in letters.characters) {
pushLetter(letter);
}
}

void popLetter() {
if (_finished) {
return;
}

_currentWord = _currentWord.substring(0, math.max(0, _currentWord.length - 1));
print("(pop)");
notifyListeners();
}

SubmitResult submit() {
if (_finished) {
return SubmitResult.win;
}

if (_currentWord.length < 5) {
return SubmitResult.notEnoughLetters;
}

if (_currentWord == _secretWord) {
_finished = true;
_saveCurrentWord();
notifyListeners();
return SubmitResult.win;
}

if (_currentAttempt == _attempts) {
print("Your word was $_secretWord");

_finished = true;
_saveCurrentWord();
notifyListeners();
return SubmitResult.lose;
}

if (!_isCurrentWordValid()) {
notifyListeners();
return SubmitResult.noSuchWord;
}

_saveCurrentWord();
notifyListeners();
return SubmitResult.incorrectWord;
}

void restart() {
_attempts = 6;
_currentAttempt = 1;
_currentWord = "";
_secretWord = "";
_guesses = [];
_finished = false;
_usedLetters = {};
}

WordMatchResult? lastGuessLetterMatchResult() {
return _guesses.lastOrNull;
}

bool _isCurrentWordValid() {
return answers.contains(_currentWord.toLowerCase()) || acceptableWords.contains(_currentWord.toLowerCase());
}

void _saveCurrentWord() {
WordMatchResult wordMatch = WordMatchResult.filled(5, const Letter.empty(), growable: false);

for (int i = 0; i < 5; ++i) {
String character = _currentWord[i];
LetterMatch letterMatch = LetterMatch.noMatch;

if (character == _secretWord[i]) {
letterMatch = LetterMatch.fullMatch;
} else if (_secretWord.contains(character)) {
letterMatch = LetterMatch.partialMatch;
}

wordMatch[i] = Letter(character, letterMatch);
_usedLetters[character] = letterMatch;
}

_guesses.add(wordMatch);
_currentWord = "";
_currentAttempt++;
}

void _setSecretWord(String word) {
assert(word.length == 5);
_secretWord = word.toUpperCase();
}

void _randomizeSecretWord() {
_secretWord = answers.elementAt(math.Random().nextInt(answers.length)).toUpperCase();
}
}
30 changes: 30 additions & 0 deletions lib/game/letter.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
enum LetterMatch {
noMatch,
partialMatch,
fullMatch,
}

class Letter {
const Letter.empty()
: _character = "",
_matchResult = null;

const Letter.unmatched(String character)
: _character = character,
_matchResult = null;

const Letter(String character, LetterMatch matchResult)
: _character = character,
_matchResult = matchResult;

final String _character;
final LetterMatch? _matchResult;

String get character => _character;

LetterMatch? get matchResult => _matchResult;

bool get isEmpty => _character.isEmpty;

bool get isNotEmpty => _character.isNotEmpty;
}
Loading

0 comments on commit 0cc9e19

Please sign in to comment.