using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; namespace Wordseach { static class Program { readonly static int[,] dirs = {{1, 0}, {0, 1}, {1, 1}, {1, -1}, {-1, 0}, {0, -1}, {-1, -1}, {-1, 1}}; class Grid { public char[,] Cells = new char[nRows, nCols]; public List Solutions = new List(); public int NumAttempts; } readonly static int nRows = 10; readonly static int nCols = 10; readonly static int gridSize = nRows * nCols; readonly static int minWords = 25; readonly static Random rand = new Random(); static void Main(string[] args) { PrintResult(CreateWordSearch(ReadWords("unixdict.txt"))); } private static List ReadWords(string filename) { int maxLen = Math.Max(nRows, nCols); return System.IO.File.ReadAllLines(filename) .Select(s => s.Trim().ToLower()) .Where(s => Regex.IsMatch(s, "^[a-z]{3," + maxLen + "}$")) .ToList(); } private static Grid CreateWordSearch(List words) { int numAttempts = 0; while (++numAttempts < 100) { words.Shuffle(); var grid = new Grid(); int messageLen = PlaceMessage(grid, "Rosetta Code"); int target = gridSize - messageLen; int cellsFilled = 0; foreach (var word in words) { cellsFilled += TryPlaceWord(grid, word); if (cellsFilled == target) { if (grid.Solutions.Count >= minWords) { grid.NumAttempts = numAttempts; return grid; } else break; // grid is full but we didn't pack enough words, start over } } } return null; } private static int TryPlaceWord(Grid grid, string word) { int randDir = rand.Next(dirs.GetLength(0)); int randPos = rand.Next(gridSize); for (int dir = 0; dir < dirs.GetLength(0); dir++) { dir = (dir + randDir) % dirs.GetLength(0); for (int pos = 0; pos < gridSize; pos++) { pos = (pos + randPos) % gridSize; int lettersPlaced = TryLocation(grid, word, dir, pos); if (lettersPlaced > 0) return lettersPlaced; } } return 0; } private static int TryLocation(Grid grid, string word, int dir, int pos) { int r = pos / nCols; int c = pos % nCols; int len = word.Length; // check bounds if ((dirs[dir, 0] == 1 && (len + c) > nCols) || (dirs[dir, 0] == -1 && (len - 1) > c) || (dirs[dir, 1] == 1 && (len + r) > nRows) || (dirs[dir, 1] == -1 && (len - 1) > r)) return 0; int rr, cc, i, overlaps = 0; // check cells for (i = 0, rr = r, cc = c; i < len; i++) { if (grid.Cells[rr, cc] != 0 && grid.Cells[rr, cc] != word[i]) { return 0; } cc += dirs[dir, 0]; rr += dirs[dir, 1]; } // place for (i = 0, rr = r, cc = c; i < len; i++) { if (grid.Cells[rr, cc] == word[i]) overlaps++; else grid.Cells[rr, cc] = word[i]; if (i < len - 1) { cc += dirs[dir, 0]; rr += dirs[dir, 1]; } } int lettersPlaced = len - overlaps; if (lettersPlaced > 0) { grid.Solutions.Add($"{word,-10} ({c},{r})({cc},{rr})"); } return lettersPlaced; } private static int PlaceMessage(Grid grid, string msg) { msg = Regex.Replace(msg.ToUpper(), "[^A-Z]", ""); int messageLen = msg.Length; if (messageLen > 0 && messageLen < gridSize) { int gapSize = gridSize / messageLen; for (int i = 0; i < messageLen; i++) { int pos = i * gapSize + rand.Next(gapSize); grid.Cells[pos / nCols, pos % nCols] = msg[i]; } return messageLen; } return 0; } public static void Shuffle(this IList list) { int n = list.Count; while (n > 1) { n--; int k = rand.Next(n + 1); T value = list[k]; list[k] = list[n]; list[n] = value; } } private static void PrintResult(Grid grid) { if (grid == null || grid.NumAttempts == 0) { Console.WriteLine("No grid to display"); return; } int size = grid.Solutions.Count; Console.WriteLine("Attempts: " + grid.NumAttempts); Console.WriteLine("Number of words: " + size); Console.WriteLine("\n 0 1 2 3 4 5 6 7 8 9"); for (int r = 0; r < nRows; r++) { Console.Write("\n{0} ", r); for (int c = 0; c < nCols; c++) Console.Write(" {0} ", grid.Cells[r, c]); } Console.WriteLine("\n"); for (int i = 0; i < size - 1; i += 2) { Console.WriteLine("{0} {1}", grid.Solutions[i], grid.Solutions[i + 1]); } if (size % 2 == 1) Console.WriteLine(grid.Solutions[size - 1]); Console.ReadLine(); } } }