void InsertSplitAt(string word, int split) { Gaddag iter = this; void InsertLetter(char letter) { int index = letter - 'a'; if (iter.children[index] == null) { iter.children[index] = new Gaddag(false); } iter = iter.children[index]; } for (int i = 0; i <= split; ++i) { int index = split - i; InsertLetter(word[index]); } InsertLetter('{'); // Represents a line-reversal. Equal to 'z' + 1 for (int i = split + 1; i < word.Length; ++i) { InsertLetter(word[i]); } iter.isEndOfWord = true; iter.word = word; iter.reversePoint = split; }
public IEnumerable <SearchNode> FindChildren(Gaddag words) { var placements = State.FindPlacements(words); foreach (Placement placement in placements) { PlayerState next = new PlayerState(State); next.PlaceWord(placement); yield return(new SearchNode(next, MovesToReach + 1)); } }
public IEnumerable <Placement> FindPlacements(Gaddag words) { if (Grid.IsEmpty()) { foreach (Gaddag word in words.FindAllWords(Bank)) { Bank after = new Bank(Bank); after.TakeWord(word.word); yield return(new Placement(word.word, 0, 0, false, after)); yield return(new Placement(word.word, 0, 0, true, after)); } yield break; } IEnumerable <Placement> FindPlacementsOriented(bool vertical) { int start = (vertical ? Grid.LeftmostColumnIndex : Grid.TopRowIndex); int end = (vertical ? Grid.RightmostColumnIndex : Grid.BottomRowIndex); for (int i = start; i <= end; ++i) { if (Grid.IsEmptyLine(i, vertical)) { continue; } foreach (Placement placement in Grid.FindLinePlacements(i, vertical, Bank, words)) { yield return(placement); } } } foreach (Placement placement in FindPlacementsOriented(false)) { yield return(placement); } foreach (Placement placement in FindPlacementsOriented(true)) { yield return(placement); } }
public IEnumerable <Placement> FindLinePlacements(int lineIndex, bool vertical, Bank bank, Gaddag words) { Dictionary <int, Line> axis = vertical ? columns : rows; Line line = axis[lineIndex]; Line[] neighbors = new Line[2]; neighbors[0] = GetLineLazy(axis, lineIndex - 1); neighbors[1] = GetLineLazy(axis, lineIndex + 1); int last = int.MaxValue; for (int i = line.FrontIndex; i >= line.BackIndex; --i) { if (!line.IsEmptyAt(i)) { foreach (Placement placement in FindLinePlacementsFrom(lineIndex, i, last - i, vertical, bank, words)) { yield return(placement); } last = i - 1; } else if (!(neighbors[0].IsEmptyAt(i) && neighbors[1].IsEmptyAt(i))) { last = i; } } }
public IEnumerable <Placement> FindLinePlacementsFrom(int lineIndex, int start, int frontLeeway, bool vertical, Bank startingBank, Gaddag words) { Dictionary <int, Line> axis = vertical ? columns : rows; Line line = axis[lineIndex]; Line[] neighbors = new Line[2]; neighbors[0] = GetLineLazy(axis, lineIndex - 1); neighbors[1] = GetLineLazy(axis, lineIndex + 1); Stack <(Gaddag, int, Bank)> nodes = new Stack <(Gaddag, int, Bank)>(); nodes.Push((words, start, startingBank)); while (nodes.Count != 0) { (Gaddag node, int index, Bank bank) = nodes.Pop(); if (line.IsEmptyAt(index)) { if (!(neighbors[0].IsEmptyAt(index) && neighbors[1].IsEmptyAt(index))) { continue; } for (char c = 'a'; c <= 'z'; ++c) { if (!bank.HasLetter(c) || node[c] == null) { continue; } Bank after = new Bank(bank); after.TakeLetter(c); nodes.Push((node[c], index - 1, after)); } if (node['{'] != null) { foreach (Gaddag word in node['{'].FindAllWords(bank)) { if (word.word.Length - word.reversePoint >= frontLeeway) { continue; } Bank after = new Bank(bank); after.TakeWord(word.word.Substring(word.reversePoint + 1)); if (Enumerable.SequenceEqual(startingBank.letters, after.letters)) { continue; } yield return(new Placement(word.word, lineIndex, start - word.reversePoint, vertical, after)); } } } else { char c = line[index]; if (node[c] != null) { nodes.Push((node[c], index - 1, bank)); } } } }
public static void Main(string[] args) { var query = from line in File.ReadLines(@"C:\Users\undoall\source\repos\BananagramsAI\BananagramsAI\shortwords.txt") where line.All(c => "abcdefghijklmnopqrstuvwxyz".Contains(c)) select line; List <string> wordList = query.ToList(); Gaddag words = new Gaddag(false); foreach (string word in wordList) { words.InsertWord(word); } float Heuristic(SearchNode node) { return((float)node.State.Bank.Size); //return (1 - node.State.Bank.CalculateValue(wordList)) * node.State.Bank.Size; } List <char> pile = new List <char>(); for (int i = 0; i < 2; ++i) { pile.AddRange("J, K, Q, X, Z".ToLower().Split(',').Select(w => w.Trim()[0])); } for (int i = 0; i < 3; ++i) { pile.AddRange("B, C, F, H, M, P, V, W, Y".ToLower().Split(',').Select(w => w.Trim()[0])); } pile.AddRange(Enumerable.Repeat('g', 4)); pile.AddRange(Enumerable.Repeat('l', 5)); for (int i = 0; i < 6; ++i) { pile.AddRange("D, S, U".ToLower().Split(',').Select(w => w.Trim()[0])); } pile.AddRange(Enumerable.Repeat('n', 8)); pile.AddRange(Enumerable.Repeat('t', 9)); pile.AddRange(Enumerable.Repeat('r', 9)); pile.AddRange(Enumerable.Repeat('o', 11)); pile.AddRange(Enumerable.Repeat('i', 12)); pile.AddRange(Enumerable.Repeat('a', 13)); pile.AddRange(Enumerable.Repeat('e', 18)); int num_taking = 40; Random rng = new Random(); int[] temp = new int[26]; for (int i = 0; i < num_taking; ++i) { int index = rng.Next(0, pile.Count); temp[pile[index] - 'a'] += 1; pile.RemoveAt(index); } Bank bank = new Bank(temp); Grid grid = new Grid(); SimplePriorityQueue <SearchNode> queue = new SimplePriorityQueue <SearchNode>(); SearchNode root = new SearchNode(new PlayerState(bank, grid), 0); queue.Enqueue(root, num_taking); int count = 0; PlayerState BestFirstSearch(PlayerState start) { for (; ;) { SearchNode node; while (!queue.TryDequeue(out node)) { ; } //SearchNode node = queue.Dequeue(); Interlocked.Increment(ref count); //Console.Clear(); //node.State.Grid.Display(); if (count % 1000 == 0) { Console.WriteLine("({0}) got node with bank size {1}", count, node.State.Bank.Size); } foreach (SearchNode child in node.FindChildren(words)) { if (child.State.Bank.Size == 0) { Console.WriteLine("Solution found!"); child.State.Grid.Display(); Console.WriteLine("Total number of nodes examined: {0}", count); Environment.Exit(Environment.ExitCode); return(child.State); } queue.Enqueue(child, Heuristic(child)); } } } Console.Write("Bank: "); for (char c = 'a'; c <= 'z'; ++c) { for (int i = 0; i < bank.letters[c - 'a']; ++i) { Console.Write(c); } } Console.WriteLine(); Console.WriteLine("Searching for solution..."); int num_threads = 1; Task[] tasks = new Task[num_threads]; for (int i = 0; i < num_threads; ++i) { tasks[i] = Task.Run(() => BestFirstSearch(new PlayerState(bank, grid))); } tasks[0].Wait(); /* * PlayerState state = new PlayerState(bank, grid); * List<Placement> placements; * for (int i = 0; i < 20; ++i) { * Console.WriteLine(); * placements = state.FindPlacements(wordsBlock); * Console.Write("From " + placements.Count + " possible moves, placing: "); * Placement placement = placements[rng.Next(0, placements.Count)]; * * * Console.WriteLine(placement.word); * state.PlaceWord(placement); * state.Grid.Display(); * for (char c = 'a'; c <= 'z'; ++c) { * if (state.Bank.HasLetter(c)) { * Console.Write(c); * } * } * Console.WriteLine(); * } */ }