diff --git a/android/app/build.gradle b/android/app/build.gradle index a4908e7..a2862e5 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -49,7 +49,7 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.example.wordle" + applicationId "com.linloir.wordle" minSdkVersion flutter.minSdkVersion targetSdkVersion flutter.targetSdkVersion versionCode flutterVersionCode.toInteger() diff --git a/lib/display_pannel.dart b/lib/display_pannel.dart index 1ace43e..7ed381d 100644 --- a/lib/display_pannel.dart +++ b/lib/display_pannel.dart @@ -1,7 +1,7 @@ /* * @Author : Linloir * @Date : 2022-03-05 20:56:05 - * @LastEditTime : 2022-03-07 12:03:43 + * @LastEditTime : 2022-03-07 14:37:33 * @Description : The display widget of the wordle game */ @@ -28,7 +28,7 @@ class _WordleDisplayWidgetState extends State with TickerPr void _validationAnimation(List validation) async { onAnimation = true; bool result = true; - for(int i = 0; i < 5; i++) { + for(int i = 0; i < 5 && onAnimation; i++) { setState((){ inputs[r][i]["State"] = validation[i]; }); @@ -37,6 +37,9 @@ class _WordleDisplayWidgetState extends State with TickerPr } await Future.delayed(const Duration(seconds: 1)); } + if(!onAnimation) { + return; + } mainBus.emit(event: "AnimationStops", args: []); onAnimation = false; r++; @@ -212,7 +215,7 @@ class _WordleDisplayWidgetState extends State with TickerPr c++; }); } - else { + else if(onAnimation){ return true; } } diff --git a/lib/generator.dart b/lib/generator.dart index f9f1f84..978ac55 100644 --- a/lib/generator.dart +++ b/lib/generator.dart @@ -1,7 +1,7 @@ /* * @Author : Linloir * @Date : 2022-03-06 15:03:57 - * @LastEditTime : 2022-03-07 11:16:16 + * @LastEditTime : 2022-03-07 15:55:48 * @Description : Word generator */ @@ -11,55 +11,69 @@ import 'dart:math'; abstract class Words { static Set dataBase = {}; - static int _length = 0; + static Set dictionary = {}; + static int _length = 5; static String _cache = ""; //static Map explainations = {}; static Future importWordsDatabase({int length = 5}) async { //explainations.clear(); - if(length != _length || dataBase.isEmpty){ + if(length != _length || dataBase.isEmpty || dictionary.isEmpty){ _length = length; dataBase.clear(); _cache = ""; - var data = await rootBundle.loadString('assets/popular.txt'); - // LineSplitter.split(data).forEach((line) { - // int seperatePos = line.indexOf(','); - // if(seperatePos != length + 2) { - // return; - // } - // var word = line.substring(1, seperatePos - 1); - // var expl = line.substring(seperatePos + 2, line.length - 1); - // dataBase.add(word); - // explainations[word] = expl; - // }); - LineSplitter.split(data).forEach((line) { - if(line.length == length && line != _cache) { - dataBase.add(line.toLowerCase()); - } - _cache = line + "s"; - }); + try { + var data = await rootBundle.loadString('assets/popular.txt'); + LineSplitter.split(data).forEach((line) { + if(line.length == length && dataBase.lookup(line.substring(0,length - 1)) == null && dataBase.lookup(line.substring(0, length - 2)) == null) { + dataBase.add(line.toLowerCase()); + } + _cache = line; + }); + } catch (e) { + throw "Failed loading question database"; + } + try { + var data = await rootBundle.loadString('assets/unixWords.txt'); + LineSplitter.split(data).forEach((line) { + if(line.length == length && dictionary.lookup(line.substring(0,length - 1)) == null && dictionary.lookup(line.substring(0, length - 2)) == null) { + dictionary.add(line.toLowerCase()); + } + _cache = line; + }); + } catch (e) { + throw "Failed loading validation database"; + } } if(dataBase.isEmpty) { - return false; + throw "Empty question database"; + } + else if(dictionary.isEmpty) { + throw "Empty validation database"; } return true; } - static Future generateWord() async{ + static Future generateWord() async { int bound = dataBase.length; - if(bound == 0) { - var import = await Words.importWordsDatabase(); - if(!import) { - return null; - } - bound = dataBase.length; - } + if(bound == 0) { + try{ + await Words.importWordsDatabase(length: _length); + } catch (e) { + return 'crash'; + } + bound = dataBase.length; + } var rng = Random(); - return dataBase.elementAt(rng.nextInt(bound)); + String res = dataBase.elementAt(rng.nextInt(bound)); + if(dictionary.lookup(res) == null) { + dictionary.add(res); + } + return res; } static bool isWordValidate(String word) { - return dataBase.lookup(word.toLowerCase()) != null; + return dictionary.lookup(word.toLowerCase()) != null; } } diff --git a/lib/main.dart b/lib/main.dart index 0f51ae2..f02f13d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,7 +1,7 @@ /* * @Author : Linloir * @Date : 2022-03-05 20:21:34 - * @LastEditTime : 2022-03-07 09:20:28 + * @LastEditTime : 2022-03-07 14:40:28 * @Description : */ import 'package:flutter/material.dart'; @@ -59,73 +59,105 @@ class _MyAppState extends State { } } -class HomePage extends StatelessWidget { +class HomePage extends StatefulWidget { const HomePage({Key? key}) : super(key: key); + @override + State createState() => _HomePageState(); +} + +class _HomePageState extends State { + bool _ignorance = false; + @override Widget build(BuildContext context) { return FutureBuilder( future: Words.importWordsDatabase(), builder: (context, snapshot) { - if(snapshot.connectionState == ConnectionState.done) { - return Scaffold( - body: Center( - child: Padding( - padding: const EdgeInsets.all(50.0), - child: AspectRatio( - aspectRatio: 16 / 9, - child: OutlinedButton( - child: Padding( - padding: const EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 15.0), - child: Align( - alignment: Alignment.centerLeft, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'OFFLINE PLAYGROUND', - style: TextStyle( - color: Theme.of(context).brightness == Brightness.dark ? Colors.white : Colors.grey[850]!, - fontSize: 20.0, - fontWeight: FontWeight.bold + if(snapshot.connectionState == ConnectionState.done || _ignorance) { + if(snapshot.hasData || _ignorance){ + return Scaffold( + body: Center( + child: Padding( + padding: const EdgeInsets.all(50.0), + child: AspectRatio( + aspectRatio: 16 / 9, + child: OutlinedButton( + child: Padding( + padding: const EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 15.0), + child: Align( + alignment: Alignment.centerLeft, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'OFFLINE PLAYGROUND', + style: TextStyle( + color: Theme.of(context).brightness == Brightness.dark ? Colors.white : Colors.grey[850]!, + fontSize: 20.0, + fontWeight: FontWeight.bold + ), ), - ), - // Padding( - // padding: const EdgeInsets.symmetric(vertical: 8.0), - // child: Container( - // width: 80.0, - // height: 8.0, - // decoration: BoxDecoration( - // color: Colors.grey[800], - // borderRadius: BorderRadius.circular(3.5), - // ), - // ), - // ), - Text( - 'Play Wordle game offline using local word database', - style: TextStyle( - color: Colors.grey[500], - fontSize: 12.0, + // Padding( + // padding: const EdgeInsets.symmetric(vertical: 8.0), + // child: Container( + // width: 80.0, + // height: 8.0, + // decoration: BoxDecoration( + // color: Colors.grey[800], + // borderRadius: BorderRadius.circular(3.5), + // ), + // ), + // ), + Text( + 'Play Wordle game offline using local word database', + style: TextStyle( + color: Colors.grey[500], + fontSize: 12.0, + ), ), - ), - ], + ], + ), ), ), - ), - style: ButtonStyle( - shape: MaterialStateProperty.all(RoundedRectangleBorder(borderRadius: BorderRadius.circular(10))), - padding: MaterialStateProperty.all(const EdgeInsets.all(0)), - ), - onPressed: () { - Navigator.of(context).pushNamed("/Offline"); - mainBus.emit(event: "NewGame", args: []); - } - ) + style: ButtonStyle( + shape: MaterialStateProperty.all(RoundedRectangleBorder(borderRadius: BorderRadius.circular(10))), + padding: MaterialStateProperty.all(const EdgeInsets.all(0)), + ), + onPressed: () async { + Navigator.of(context).pushNamed("/Offline"); + //Future.delayed(const Duration(milliseconds: 10)).then((e) => mainBus.emit(event: "NewGame", args: [])); + } + ) + ), + ) + ), + ); + } + else { + return Container( + color: Colors.black38, + child: AlertDialog( + title: const Text('Failure'), + content: Text(snapshot.error as String), + actions: [ + TextButton( + child: const Text('Retry'), + onPressed: () => setState(() {}), ), - ) - ), - ); + TextButton( + child: const Text('Ignore'), + onPressed: () { + setState((){ + _ignorance = true; + }); + }, + ), + ], + ), + ); + } } else { return Scaffold( diff --git a/lib/offline.dart b/lib/offline.dart index ecc0d15..7225e16 100644 --- a/lib/offline.dart +++ b/lib/offline.dart @@ -1,7 +1,7 @@ /* * @Author : Linloir * @Date : 2022-03-05 20:41:41 - * @LastEditTime : 2022-03-07 11:05:14 + * @LastEditTime : 2022-03-07 14:40:37 * @Description : Offline page */ diff --git a/lib/validation_provider.dart b/lib/validation_provider.dart index 4d6dd81..1280439 100644 --- a/lib/validation_provider.dart +++ b/lib/validation_provider.dart @@ -1,12 +1,11 @@ /* * @Author : Linloir * @Date : 2022-03-05 21:40:51 - * @LastEditTime : 2022-03-07 11:15:55 + * @LastEditTime : 2022-03-07 14:40:46 * @Description : Validation Provider class */ import 'package:flutter/material.dart'; -import 'show_dialogs.dart'; import './event_bus.dart'; import './generator.dart'; @@ -39,23 +38,11 @@ class _ValidationProviderState extends State { _newGame(); } - void _newGame() async{ - showLoadingDialog(context: context); - var generated = await Words.generateWord(); - Navigator.of(context).pop(); - while(generated == null) { - var retry = await showFailedDialog(context: context); - if(retry == null) { - Navigator.of(context).popUntil(ModalRoute.withName('/')); - break; - } - else { - showLoadingDialog(context: context); - generated = await Words.generateWord(); - Navigator.of(context).pop(); - } - } - answer = generated ?? ""; + void _newGame() async { + curAttempt = ""; + curAttemptCount = 0; + acceptInput = true; + answer = await Words.generateWord(); answer = answer.toUpperCase(); letterMap = {}; answer.split('').forEach((c) { @@ -63,9 +50,6 @@ class _ValidationProviderState extends State { letterMap[c] = letterMap[c]! + 1; }); letterMap = Map.unmodifiable(letterMap); - curAttempt = ""; - curAttemptCount = 0; - acceptInput = true; } void _onGameEnd(dynamic args) { @@ -110,6 +94,7 @@ class _ValidationProviderState extends State { @override void initState(){ super.initState(); + _newGame(); mainBus.onBus(event: "NewGame", onEvent: _onNewGame); mainBus.onBus(event: "Result", onEvent: _onGameEnd); } diff --git a/pubspec.yaml b/pubspec.yaml index 681548a..3622126 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 0.3.9+0939 +version: 0.3.7+1451 environment: sdk: ">=2.16.1 <3.0.0"