diff --git a/lib/main.dart b/lib/main.dart index 26e3600..eda0713 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,7 @@ import 'dart:isolate'; import 'dart:math'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import "./algorithm.dart"; @@ -48,11 +49,16 @@ class _MyHomePageState extends State { String path = ""; DictionaryType dictionaryType = DictionaryType.semiReasonableScrabble; bool isGenerating = false; + Trie fullScrabbleTrie = Trie(); @override void initState() { super.initState(); generateGameFile(); + + for (var word in scrabbleComplete) { + fullScrabbleTrie.insert(word); + } } @override @@ -182,6 +188,7 @@ class _MyHomePageState extends State { playerCount: playerCount, path: path, dictionaryType: dictionaryType, + fullScrabbleTrie: fullScrabbleTrie, ), ], ), @@ -257,6 +264,7 @@ class AlgorithmShower extends StatefulWidget { final int playerCount; final String path; final DictionaryType dictionaryType; + final Trie fullScrabbleTrie; const AlgorithmShower({ Key? key, @@ -266,6 +274,7 @@ class AlgorithmShower extends StatefulWidget { required this.playerCount, required this.path, required this.dictionaryType, + required this.fullScrabbleTrie, }) : super(key: key); @override @@ -273,20 +282,17 @@ class AlgorithmShower extends StatefulWidget { } class _AlgorithmShowerState extends State { + Future>? future; + bool isTurn = false; Map optimalGame = {}; List> sortedLetters = []; String? showWords; - Trie fullScrabbleTrie = Trie(); @override void initState() { super.initState(); _initializeAlgorithm(); - - for (var word in scrabbleComplete) { - fullScrabbleTrie.insert(word); - } } @override @@ -300,8 +306,6 @@ class _AlgorithmShowerState extends State { } void _initializeAlgorithm() { - // I extrapolated this out of build just to be unnecessarily safe (turns out it was a good idea) - if (!widget.dictionaryTrie.hasChildren(widget.path) || widget.dictionaryTrie.has(widget.path)) { return; @@ -314,24 +318,78 @@ class _AlgorithmShowerState extends State { optimalGame.clear(); sortedLetters.clear(); - if (isTurn) { - var temporaryDictionary = widget.dictionaryTrie.root.walk(widget.path)!; + future = compute(determinePercentageIsolate, [ + widget.dictionaryTrie, + widget.gameData, + widget.playerCount, + widget.path, + isTurn, + ]); + } - for (var letter in letters) { - if (!temporaryDictionary.hasChild(letter)) { - continue; - } - optimalGame[letter] = determinePercentage( - widget.path + letter, widget.gameData, widget.playerCount); - } + static List determinePercentageIsolate(List arguments) { + var isTurn = arguments[4] as bool; + + if (!isTurn) { + return [null, null]; + } + + var dictionaryTrie = arguments[0] as Trie; + var gameData = arguments[1] as Map; + var playerCount = arguments[2] as int; + var path = arguments[3] as String; + + var temporaryDictionary = dictionaryTrie.root.walk(path)!; - sortedLetters.addAll(optimalGame.entries.toList() - ..sort((a, b) => b.value.compareTo(a.value))); + var optimalGame = {}; + var sortedLetters = >[]; + + for (var letter in letters) { + if (!temporaryDictionary.hasChild(letter)) { + continue; + } + optimalGame[letter] = + determinePercentage(path + letter, gameData, playerCount); } + + sortedLetters.addAll(optimalGame.entries.toList() + ..sort((a, b) => b.value.compareTo(a.value))); + + return [optimalGame, sortedLetters]; } @override Widget build(BuildContext context) { + return FutureBuilder>( + future: future, + builder: (BuildContext context, AsyncSnapshot> snapshot) { + switch (snapshot.connectionState) { + case ConnectionState.none: + return const SizedBox(); + case ConnectionState.waiting: + return const Padding( + padding: EdgeInsets.symmetric(vertical: 16.0), + child: CircularProgressIndicator(), + ); + case ConnectionState.active: + return const SizedBox(); + case ConnectionState.done: + if (snapshot.hasError) { + return Text("Error: ${snapshot.error}"); + } + + if (snapshot.data![0] != null) { + optimalGame = snapshot.data![0] as Map; + sortedLetters = + snapshot.data![1] as List>; + } + + return loadedInterface(context); + } + }); + } + + RenderObjectWidget loadedInterface(BuildContext context) { if (widget.dictionaryTrie.has(widget.path)) { return const Padding( padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 12.0), @@ -354,7 +412,7 @@ class _AlgorithmShowerState extends State { textAlign: TextAlign.center, ), const SizedBox(height: 24), - if (fullScrabbleTrie.hasChildren(widget.path)) + if (widget.fullScrabbleTrie.hasChildren(widget.path)) const Text( "Note: Words exist in the full Scrabble dictionary. Change the dictionary type to view them.", style: TextStyle(fontSize: 18, fontWeight: FontWeight.w300),