From 9a67a4b243f5c75e68f41868833d0655e638f32a Mon Sep 17 00:00:00 2001 From: David Galehouse Date: Sat, 18 Mar 2017 01:46:18 -0400 Subject: [PATCH] Include default dictionary as part of solver Conceptually this makes sense. The Wordament dictionary is essential to how boards are solved, so we need to start maintaing a dictionary and working closer to what Wordament actually uses. --- Daves.WordamentSolver.UI/App.config | 9 ---- .../ApplicationEntryPoint.cs | 9 ++-- .../Daves.WordamentSolver.UI.csproj | 4 -- .../Helpers/FileHelper.cs | 8 --- .../Presenters/SolverPresenter.cs | 9 ++-- Daves.WordamentSolver.UI/Views/SolverForm.cs | 18 +++---- .../AssemblyInitializer.cs | 4 +- .../Daves.WordamentSolver.UnitTests.csproj | 6 --- .../WordSorters/WordSorterTests.cs | 4 +- Daves.WordamentSolver.sln | 1 + Daves.WordamentSolver/Board.cs | 8 +-- .../Daves.WordamentSolver.csproj | 15 ++++-- .../Dictionary.txt | 0 Daves.WordamentSolver/SimpleSolution.cs | 2 + Daves.WordamentSolver/Solution.cs | 9 ++-- Daves.WordamentSolver/Tile.cs | 2 +- Daves.WordamentSolver/Tiles/BasicTile.cs | 2 +- Daves.WordamentSolver/Tiles/DigramTile.cs | 2 +- Daves.WordamentSolver/Tiles/EitherOrTile.cs | 2 +- Daves.WordamentSolver/Tiles/PrefixTile.cs | 2 +- Daves.WordamentSolver/Tiles/SuffixTile.cs | 2 +- PackagingInstructions.txt | 52 +++++++++++++++++++ README.md | 14 ++--- 23 files changed, 105 insertions(+), 79 deletions(-) delete mode 100644 Daves.WordamentSolver.UI/App.config rename Daves.WordamentSolver.UI/TWL06Dictionary.txt => Daves.WordamentSolver/Dictionary.txt (100%) create mode 100644 PackagingInstructions.txt diff --git a/Daves.WordamentSolver.UI/App.config b/Daves.WordamentSolver.UI/App.config deleted file mode 100644 index 970a627..0000000 --- a/Daves.WordamentSolver.UI/App.config +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/Daves.WordamentSolver.UI/ApplicationEntryPoint.cs b/Daves.WordamentSolver.UI/ApplicationEntryPoint.cs index ddd6cf6..4aa8a5d 100644 --- a/Daves.WordamentSolver.UI/ApplicationEntryPoint.cs +++ b/Daves.WordamentSolver.UI/ApplicationEntryPoint.cs @@ -1,8 +1,7 @@ -using System; -using System.Windows.Forms; -using Daves.WordamentSolver.UI.Helpers; -using Daves.WordamentSolver.UI.Presenters; +using Daves.WordamentSolver.UI.Presenters; using Daves.WordamentSolver.UI.Views; +using System; +using System.Windows.Forms; namespace Daves.WordamentSolver.UI { @@ -16,7 +15,7 @@ private static void Main() try { - Solution.SetDictionary(FileHelper.ReadDictionaryFile()); + Solution.SetDictionary(); } catch (Exception e) { diff --git a/Daves.WordamentSolver.UI/Daves.WordamentSolver.UI.csproj b/Daves.WordamentSolver.UI/Daves.WordamentSolver.UI.csproj index 21b1895..5d3ac6a 100644 --- a/Daves.WordamentSolver.UI/Daves.WordamentSolver.UI.csproj +++ b/Daves.WordamentSolver.UI/Daves.WordamentSolver.UI.csproj @@ -90,7 +90,6 @@ Resources.resx True - SettingsSingleFileGenerator Settings.Designer.cs @@ -103,9 +102,6 @@ - - PreserveNewest - diff --git a/Daves.WordamentSolver.UI/Helpers/FileHelper.cs b/Daves.WordamentSolver.UI/Helpers/FileHelper.cs index cd4ef79..b179854 100644 --- a/Daves.WordamentSolver.UI/Helpers/FileHelper.cs +++ b/Daves.WordamentSolver.UI/Helpers/FileHelper.cs @@ -1,18 +1,10 @@ using System.Collections.Generic; -using System.Configuration; using System.IO; namespace Daves.WordamentSolver.UI.Helpers { - // Not sure where to do file access, but keeping it here seems better than doing it all throughout the app. public static class FileHelper { - public static IEnumerable ReadDictionaryFile() - => ReadLines(ConfigurationManager.AppSettings["DictionaryFilePath"]); - - public static IEnumerable ReadLines(string filePath) - => File.ReadLines(filePath); - public static string[] ReadAllLines(string filePath) => File.ReadAllLines(filePath); diff --git a/Daves.WordamentSolver.UI/Presenters/SolverPresenter.cs b/Daves.WordamentSolver.UI/Presenters/SolverPresenter.cs index 9b34e4c..cf04b7e 100644 --- a/Daves.WordamentSolver.UI/Presenters/SolverPresenter.cs +++ b/Daves.WordamentSolver.UI/Presenters/SolverPresenter.cs @@ -1,8 +1,8 @@ -using System; +using Daves.WordamentSolver.UI.Contracts; +using Daves.WordamentSolver.UI.Helpers; +using System; using System.Collections.Generic; using System.Linq; -using Daves.WordamentSolver.UI.Contracts; -using Daves.WordamentSolver.UI.Helpers; namespace Daves.WordamentSolver.UI.Presenters { @@ -111,8 +111,7 @@ private void View_LoadFromFile(string filePath) int?[] tilePoints = new int?[BoardSize]; for (int i = 0; i < BoardSize; ++i) { - int points; - if (int.TryParse(lines[i + BoardSize], out points)) + if (int.TryParse(lines[i + BoardSize], out int points)) { tilePoints[i] = points; } diff --git a/Daves.WordamentSolver.UI/Views/SolverForm.cs b/Daves.WordamentSolver.UI/Views/SolverForm.cs index d1135dd..5a0f2e2 100644 --- a/Daves.WordamentSolver.UI/Views/SolverForm.cs +++ b/Daves.WordamentSolver.UI/Views/SolverForm.cs @@ -1,11 +1,11 @@ -using System; +using Daves.WordamentSolver.UI.Contracts; +using Daves.WordamentSolver.UI.Helpers; +using Daves.WordamentSolver.UI.Properties; +using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Windows.Forms; -using Daves.WordamentSolver.UI.Contracts; -using Daves.WordamentSolver.UI.Helpers; -using Daves.WordamentSolver.UI.Properties; namespace Daves.WordamentSolver.UI.Views { @@ -156,10 +156,9 @@ private void ClearBoardButton_Click(object sender, EventArgs e) private void SaveAsToolStripMenuItem_Click(object sender, EventArgs e) { - SaveFileDialog dialog = new SaveFileDialog + var dialog = new SaveFileDialog { - Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*", - FilterIndex = 1 + Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*" }; if (dialog.ShowDialog() == DialogResult.OK) @@ -170,10 +169,9 @@ private void SaveAsToolStripMenuItem_Click(object sender, EventArgs e) private void LoadToolStripMenuItem_Click(object sender, EventArgs e) { - OpenFileDialog dialog = new OpenFileDialog + var dialog = new OpenFileDialog { - Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*", - FilterIndex = 1 + Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*" }; if (dialog.ShowDialog() == DialogResult.OK) diff --git a/Daves.WordamentSolver.UnitTests/AssemblyInitializer.cs b/Daves.WordamentSolver.UnitTests/AssemblyInitializer.cs index 2503a3d..0f8d3b0 100644 --- a/Daves.WordamentSolver.UnitTests/AssemblyInitializer.cs +++ b/Daves.WordamentSolver.UnitTests/AssemblyInitializer.cs @@ -1,6 +1,4 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -using System.IO; -using System.Linq; namespace Daves.WordamentSolver.UnitTests { @@ -9,6 +7,6 @@ public static class AssemblyInitializer { [AssemblyInitialize] public static void InitializeAssembly(TestContext context) - => Solution.SetDictionary(File.ReadLines(@"TWL06Dictionary.txt")); + => Solution.SetDictionary(); } } diff --git a/Daves.WordamentSolver.UnitTests/Daves.WordamentSolver.UnitTests.csproj b/Daves.WordamentSolver.UnitTests/Daves.WordamentSolver.UnitTests.csproj index 31a1789..c6ec981 100644 --- a/Daves.WordamentSolver.UnitTests/Daves.WordamentSolver.UnitTests.csproj +++ b/Daves.WordamentSolver.UnitTests/Daves.WordamentSolver.UnitTests.csproj @@ -65,12 +65,6 @@ Daves.WordamentSolver - - - TWL06Dictionary.txt - PreserveNewest - - diff --git a/Daves.WordamentSolver.UnitTests/WordSorters/WordSorterTests.cs b/Daves.WordamentSolver.UnitTests/WordSorters/WordSorterTests.cs index 52893fc..1631f51 100644 --- a/Daves.WordamentSolver.UnitTests/WordSorters/WordSorterTests.cs +++ b/Daves.WordamentSolver.UnitTests/WordSorters/WordSorterTests.cs @@ -1,6 +1,6 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; +using Daves.WordamentSolver.WordSorters; +using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Linq; -using Daves.WordamentSolver.WordSorters; namespace Daves.WordamentSolver.UnitTests.WordSorters { diff --git a/Daves.WordamentSolver.sln b/Daves.WordamentSolver.sln index fe121c9..7162d6b 100644 --- a/Daves.WordamentSolver.sln +++ b/Daves.WordamentSolver.sln @@ -9,6 +9,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution ProjectSection(SolutionItems) = preProject .gitignore = .gitignore LICENSE = LICENSE + PackagingInstructions.txt = PackagingInstructions.txt README.md = README.md SampleBoard.txt = SampleBoard.txt EndProjectSection diff --git a/Daves.WordamentSolver/Board.cs b/Daves.WordamentSolver/Board.cs index c6c8415..ef852d4 100644 --- a/Daves.WordamentSolver/Board.cs +++ b/Daves.WordamentSolver/Board.cs @@ -17,7 +17,7 @@ public Board(int boardHeight, int boardWidth, { BoardHeight = boardHeight; BoardWidth = boardWidth; - _basicTilesValues = basicTileValues ?? EnglishBasicTileValues; + _basicTilesValues = basicTileValues ?? BasicTileValues; Tiles = tileStrings.Zip(tilePoints, (s, p) => new { @string = s, points = p }) .Select((a, i) => CreateTile( @@ -49,7 +49,7 @@ public Board(string[,] tileStrings, int?[,] tilePoints, { BoardHeight = tileStrings.GetLength(0); BoardWidth = tileStrings.GetLength(1); - _basicTilesValues = basicTileValues ?? EnglishBasicTileValues; + _basicTilesValues = basicTileValues ?? BasicTileValues; var tiles = new Tile[BoardSize]; for (int r = 0; r < BoardHeight; ++r) @@ -74,7 +74,7 @@ public Board(string[,] tileStrings, int?[,] tilePoints, public int BoardSize => BoardHeight * BoardWidth; public virtual IReadOnlyList Tiles { get; protected set; } - public virtual Tile CreateTile(int row, int column, int position, string @string, int? points) + protected virtual Tile CreateTile(int row, int column, int position, string @string, int? points) => BasicTile.TryCreate(row, column, position, @string, points, _basicTilesValues) ?? DigramTile.TryCreate(row, column, position, @string, points, _basicTilesValues) ?? PrefixTile.TryCreate(row, column, position, @string, points, _basicTilesValues) @@ -124,7 +124,7 @@ public virtual IEnumerable GetTilesNoMoreThanOneMoveAway(Tile tile) } } - public static readonly IReadOnlyDictionary EnglishBasicTileValues = new Dictionary(new CaseInsensitiveCharEqualityComparer()) + public static readonly IReadOnlyDictionary BasicTileValues = new Dictionary(new CaseInsensitiveCharEqualityComparer()) {{'A', 2}, {'B', 5}, {'C', 3}, {'D', 3}, {'E', 1}, {'F', 5}, {'G', 4}, {'H', 4}, {'I', 2}, {'J', 10}, {'K', 6}, {'L', 3}, {'M', 4}, {'N', 2}, {'O', 2}, {'P', 4}, {'Q', 8}, {'R', 2}, {'S', 2}, {'T', 2}, {'U', 4}, {'V', 6}, {'W', 6}, {'X', 9}, {'Y', 5}, {'Z', 8}}; diff --git a/Daves.WordamentSolver/Daves.WordamentSolver.csproj b/Daves.WordamentSolver/Daves.WordamentSolver.csproj index ed49d0b..d5f2d4b 100644 --- a/Daves.WordamentSolver/Daves.WordamentSolver.csproj +++ b/Daves.WordamentSolver/Daves.WordamentSolver.csproj @@ -11,13 +11,20 @@ https://github.com/davghouse/Daves.WordamentSolver.git git wordament, solver, trie, boggle, board - 2.0.0: Support many-to-many word-path relationships, case-insensitivity, language extensibility, and a faster simple solution alternative + 2.1.0: Included default dictionary +2.0.0: Support many-to-many word-path relationships, case-insensitivity, language extensibility, and a faster simple solution alternative 1.4.0: Implement IReadOnlyList/ToString for convenience 1.3.0: Solution tweaks 1.2.0: Better Board extensibility 1.1.0: More flexible Board constructors - 2.0.0 - 2.0.0.0 - 2.0.0.0 + 2.1.0 + 2.1.0.0 + 2.1.0.0 + + + PreserveNewest + false + + \ No newline at end of file diff --git a/Daves.WordamentSolver.UI/TWL06Dictionary.txt b/Daves.WordamentSolver/Dictionary.txt similarity index 100% rename from Daves.WordamentSolver.UI/TWL06Dictionary.txt rename to Daves.WordamentSolver/Dictionary.txt diff --git a/Daves.WordamentSolver/SimpleSolution.cs b/Daves.WordamentSolver/SimpleSolution.cs index f871da4..8259253 100644 --- a/Daves.WordamentSolver/SimpleSolution.cs +++ b/Daves.WordamentSolver/SimpleSolution.cs @@ -15,6 +15,8 @@ public class SimpleSolution public SimpleSolution(Board board) { + if (Solution.Dictionary == null) { Solution.SetDictionary(); } + _board = board; foreach (Tile tile in _board.Tiles) diff --git a/Daves.WordamentSolver/Solution.cs b/Daves.WordamentSolver/Solution.cs index ac6dcb8..097af9d 100644 --- a/Daves.WordamentSolver/Solution.cs +++ b/Daves.WordamentSolver/Solution.cs @@ -3,6 +3,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.IO; using System.Linq; namespace Daves.WordamentSolver @@ -10,8 +11,8 @@ namespace Daves.WordamentSolver public class Solution : IReadOnlyList { protected internal static Trie Dictionary { get; protected set; } - public static void SetDictionary(IEnumerable @strings) - => Dictionary = new Trie(@strings.Where(s => s.Length > 2), new CaseInsensitiveCharEqualityComparer()); + public static void SetDictionary(IEnumerable @strings = null) + => Dictionary = new Trie((@strings ?? File.ReadLines("Dictionary.txt")).Where(s => s.Length > 2), new CaseInsensitiveCharEqualityComparer()); protected readonly Board _board; protected readonly Dictionary _stringWordMap = new Dictionary(StringComparer.OrdinalIgnoreCase); @@ -23,6 +24,8 @@ public Solution() public Solution(Board board, WordSorter wordSorter = null) { + if (Dictionary == null) { SetDictionary(); } + _board = board; foreach (Tile tile in _board.Tiles) @@ -114,7 +117,7 @@ public virtual void SortWords(WordSorter wordSorter) } public override string ToString() - => $"Total points: {TotalPoints}, Total words: {TotalWords}"; + => $"Total points: {TotalPoints}, total words: {TotalWords}"; Word IReadOnlyList.this[int index] => Words[index]; int IReadOnlyCollection.Count => TotalWords; diff --git a/Daves.WordamentSolver/Tile.cs b/Daves.WordamentSolver/Tile.cs index 8482852..dc6ac5e 100644 --- a/Daves.WordamentSolver/Tile.cs +++ b/Daves.WordamentSolver/Tile.cs @@ -15,7 +15,7 @@ protected Tile(int row, int column, int position, string @string, int? points, Position = position; String = @string; Points = points; - _basicTilesValues = basicTileValues ?? Board.EnglishBasicTileValues; + _basicTilesValues = basicTileValues ?? Board.BasicTileValues; } public int Row { get; } diff --git a/Daves.WordamentSolver/Tiles/BasicTile.cs b/Daves.WordamentSolver/Tiles/BasicTile.cs index 5f0d774..e83e934 100644 --- a/Daves.WordamentSolver/Tiles/BasicTile.cs +++ b/Daves.WordamentSolver/Tiles/BasicTile.cs @@ -12,7 +12,7 @@ protected BasicTile(int row, int column, int position, string @string, int? poin public static BasicTile TryCreate(int row, int column, int position, string @string, int? points, IReadOnlyDictionary basicTileValues = null) { - basicTileValues = basicTileValues ?? Board.EnglishBasicTileValues; + basicTileValues = basicTileValues ?? Board.BasicTileValues; return @string != null && @string.Length == 1 diff --git a/Daves.WordamentSolver/Tiles/DigramTile.cs b/Daves.WordamentSolver/Tiles/DigramTile.cs index 4badfe4..eb79dcc 100644 --- a/Daves.WordamentSolver/Tiles/DigramTile.cs +++ b/Daves.WordamentSolver/Tiles/DigramTile.cs @@ -13,7 +13,7 @@ protected DigramTile(int row, int column, int position, string @string, int? poi public static DigramTile TryCreate(int row, int column, int position, string @string, int? points, IReadOnlyDictionary basicTileValues = null) { - basicTileValues = basicTileValues ?? Board.EnglishBasicTileValues; + basicTileValues = basicTileValues ?? Board.BasicTileValues; return @string != null && @string.Length == 2 diff --git a/Daves.WordamentSolver/Tiles/EitherOrTile.cs b/Daves.WordamentSolver/Tiles/EitherOrTile.cs index 5c9990d..ca6ea62 100644 --- a/Daves.WordamentSolver/Tiles/EitherOrTile.cs +++ b/Daves.WordamentSolver/Tiles/EitherOrTile.cs @@ -12,7 +12,7 @@ protected EitherOrTile(int row, int column, int position, string @string, int? p public static EitherOrTile TryCreate(int row, int column, int position, string @string, int? points, IReadOnlyDictionary basicTileValues = null) { - basicTileValues = basicTileValues ?? Board.EnglishBasicTileValues; + basicTileValues = basicTileValues ?? Board.BasicTileValues; return @string != null && @string.Length == 3 diff --git a/Daves.WordamentSolver/Tiles/PrefixTile.cs b/Daves.WordamentSolver/Tiles/PrefixTile.cs index 85b2dbc..4df8eb5 100644 --- a/Daves.WordamentSolver/Tiles/PrefixTile.cs +++ b/Daves.WordamentSolver/Tiles/PrefixTile.cs @@ -14,7 +14,7 @@ protected PrefixTile(int row, int column, int position, string @string, int? poi public static PrefixTile TryCreate(int row, int column, int position, string @string, int? points, IReadOnlyDictionary basicTileValues = null) { - basicTileValues = basicTileValues ?? Board.EnglishBasicTileValues; + basicTileValues = basicTileValues ?? Board.BasicTileValues; return @string != null && @string.Length >= 3 diff --git a/Daves.WordamentSolver/Tiles/SuffixTile.cs b/Daves.WordamentSolver/Tiles/SuffixTile.cs index 6474385..1e525f2 100644 --- a/Daves.WordamentSolver/Tiles/SuffixTile.cs +++ b/Daves.WordamentSolver/Tiles/SuffixTile.cs @@ -13,7 +13,7 @@ protected SuffixTile(int row, int column, int position, string @string, int? poi public static SuffixTile TryCreate(int row, int column, int position, string @string, int? points, IReadOnlyDictionary basicTileValues = null) { - basicTileValues = basicTileValues ?? Board.EnglishBasicTileValues; + basicTileValues = basicTileValues ?? Board.BasicTileValues; return @string != null && @string.Length >= 3 diff --git a/PackagingInstructions.txt b/PackagingInstructions.txt new file mode 100644 index 0000000..c12a4ec --- /dev/null +++ b/PackagingInstructions.txt @@ -0,0 +1,52 @@ +I had trouble configuring the package such that the Dictionary.txt file would +appear automatically in the referencing project's output folder, next to the .dll. + +It's set to Content, Copy if newer in Daves.WordamentSolver which makes sense, but in +the .csproj I also set false to prevent the file from being included in +the root directory of referencing projects. + +Then I use Visual Studio to build the .nupkg, change the extension to .zip, unzip, edit +the .nuspec to look something like this (note the tag; that gets added by hand): + + + + + Daves.WordamentSolver + 2.1.0 + Dave + Dave + false + https://opensource.org/licenses/MIT + https://github.com/davghouse/Daves.WordamentSolver + Wordament solver that handles an arbitrary number of special tiles, finds the many-to-many word-path relationships, and approximates a best path. + 2.1.0: Included default dictionary +2.0.0: Support many-to-many word-path relationships, case-insensitivity, language extensibility, and a faster simple solution alternative +1.4.0: Implement IReadOnlyList/ToString for convenience +1.3.0: Solution tweaks +1.2.0: Better Board extensibility +1.1.0: More flexible Board constructors + © 2017 Dave + wordament, solver, trie, boggle, board + + + + + + + + + + +Then I add that build folder (at the same folder level as the .nuspec), and it contains +the Dictionary.txt file and a file called Daves.WordamentSolver.targets with these contents: + + + + + Dictionary.txt + PreserveNewest + + + + +Then zip the ~6 things in the unzipped folder again and change the extension back to .nupkg. \ No newline at end of file diff --git a/README.md b/README.md index 59f029c..dd50db7 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Dave's Wordament Solver Wordament solver that handles an arbitrary number of special tiles, finds the many-to-many word-path relationships, and approximates a best path. -Latest release [here](https://github.com/davghouse/Daves.WordamentSolver/releases/tag/v1.4.0). +Latest release [here](https://github.com/davghouse/Daves.WordamentSolver/releases/tag/v1.4.1). Solver library available as a [NuGet Package](https://www.nuget.org/packages/Daves.WordamentSolver). @@ -34,18 +34,15 @@ For example, on a board where the total path length from the words themselves wa Limitations ----------- -I'm using the TWL06 dictionary, which doesn't have 16-letter words. - +The dictionary file is based off of the TWL06 dictionary, which doesn't have 16-letter words. Wordament has something like 170 banned words, and I don't know all of them. The few I do know I haven't bothered removing from the dictionary. There are also words Wordament has that my dictionary doesn't, like s'mores spelled as smores, for instance. -I tried using SOWPODS and that was more off than TWL. +I tried using SOWPODS but that was more off than TWL. As it stands right now, the TWL dictionary is pretty close. Were the banned words removed, it might be a proper subset of the Wordament dictionary. I know for sure that SOWPODS is no where near a subset, which seems worse. - -All that being said, the dictionary is configurable through the exe.config. -Specify the name of a newline-separated dictionary and put it in the same place as the TWL06 one. +Ideally the dictionary gets maintained with new words being added as they're discovered to be missing. In the game, words have 'common' and 'uncommon' designations. I don't know how to create those designations. @@ -56,6 +53,3 @@ Either/or tiles get a fixed value of 20 points. That's what I've seen in recent games (as of 2014). Other multi-letter tiles get their individual values summed + 5. 3 or 4 might be correct more of the time, but we probably want to focus on that tile regardless. - -I'm not sure if base tiles always have the same values when not specified otherwise in high-value type boards / letter in the corners type boards. -I'm not sure if I can figure out the exact value of prefix/suffix/digram/either\or tiles.