static void Main(string[] args) { ulong totalLegalPuzzles; Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); totalLegalPuzzles = NurikabeInstance.StartMultithreadedRun(8, 4); stopwatch.Stop(); Console.WriteLine(totalLegalPuzzles); Console.WriteLine(stopwatch.Elapsed); Console.WriteLine(); Console.WriteLine("Done. Enter 'exit' to exit. Case sensitive."); string response; while ((response = Console.ReadLine()) != "exit") { Console.WriteLine("Done. Enter 'exit' to exit. Case sensitive."); } }
/// <summary> /// Starts a multithreaded run of a nurikabe puzzle. It partitions the possible patterns into the desired number of threads. /// For thread counts and puzzle sizes that do not divide evenly, the last thread does the remaining puzzles. /// This is an overloaded method that uses a start point and end point. /// </summary> /// <param name="numOfThreads">The desired number of threads to use.</param> /// <param name="sizeOfPuzzle">The length or width of an n x n nurikabe puzzle.</param> /// <param name="startPoint">The starting integer of a puzzle to work on. <strong><em>DO NOT</em></strong> start at 0. /// It is already included if this method is started at 1.</param> /// <param name="endPoint">The last integer of a puzzle to work on.</param> /// <returns></returns> public static ulong StartMultithreadedRun(int numOfThreads, int sizeOfPuzzle, ulong startPoint, ulong endPoint) { NurikabeInstance[] nurikabes = new NurikabeInstance[numOfThreads]; ThreadStart[] threadStarts = new ThreadStart[numOfThreads]; List <Thread> threads = new List <Thread>(); // There is no Math.Pow for integers. int lengthOfPattern = sizeOfPuzzle * sizeOfPuzzle; // -1 because we already account for the trivial case. ulong numberOfPatterns = endPoint - startPoint + 1; ulong shareSize = numberOfPatterns / (ulong)numOfThreads; ulong extra = numberOfPatterns % (ulong)numOfThreads; ulong sum = startPoint - 1; for (int i = 0; i < numOfThreads; i++) { nurikabes[i] = new NurikabeInstance(sum + 1, 0, lengthOfPattern, sizeOfPuzzle); sum += shareSize; if (i == numOfThreads - 1) { sum += extra; } nurikabes[i].StopPoint = sum; threadStarts[i] = new ThreadStart(nurikabes[i].GenerateLegalNurikabe); } // Set up all threads for (int i = 0; i < numOfThreads; i++) { threads.Add(new Thread(threadStarts[i])); } // Start all threads. for (int i = 0; i < numOfThreads; i++) { threads[i].Start(); } // Find better way to wait for all threads to finish. Join ties up threads. bool stillBusy = true; while (stillBusy) { stillBusy = false; for (int i = 0; i < numOfThreads; i++) { if (threads[i].IsAlive) { stillBusy = true; Thread.Sleep(1); break; } } } // Add up all puzzles. ulong totalLegalPuzzles = 0; for (int i = 0; i < numOfThreads; i++) { totalLegalPuzzles += nurikabes[i].LegalPuzzles; } //Each instance of a nurikabe puzzle includes the trivial case. if (startPoint == 1) { return(totalLegalPuzzles - (ulong)numOfThreads + 1); } else { return(totalLegalPuzzles - (ulong)numOfThreads); } }
// Extend upper limit on puzzles by using BigInteger Class. May just be too hard to go past 8. /// <summary> /// Starts a multithreaded run of a nurikabe puzzle. It partitions the possible patterns into the desired number of threads. /// For thread counts and puzzle sizes that do not divide evenly, the last thread does the remaining puzzles. /// </summary> /// <param name="numOfThreads">The desired number of threads to use.</param> /// <param name="sizeOfPuzzle">The length or width of an n x n nurikabe puzzle.</param> public static ulong StartMultithreadedRun(int numOfThreads, int sizeOfPuzzle) { NurikabeInstance[] nurikabes = new NurikabeInstance[numOfThreads]; ThreadStart[] threadStarts = new ThreadStart[numOfThreads]; List <Thread> threads = new List <Thread>(); // There is no Math.Pow for integers. int lengthOfPattern = sizeOfPuzzle * sizeOfPuzzle; // Just for the purpose of Math.Pow. Does not allow implicit conversion of int to double. double lengthOfPatternDouble = sizeOfPuzzle * sizeOfPuzzle; // -1 because we already account for the trivial case. ulong numberOfPatterns = (ulong)Math.Pow(2, lengthOfPatternDouble) - 1; ulong shareSize = numberOfPatterns / (ulong)numOfThreads; ulong extra = numberOfPatterns % (ulong)numOfThreads; ulong sum = 0; for (int i = 0; i < numOfThreads; i++) { nurikabes[i] = new NurikabeInstance(sum + 1, 0, lengthOfPattern, sizeOfPuzzle); sum += shareSize; if (i == numOfThreads - 1) { sum += extra; } nurikabes[i].StopPoint = sum; threadStarts[i] = new ThreadStart(nurikabes[i].GenerateLegalNurikabe); } // Set up all threads for (int i = 0; i < numOfThreads; i++) { threads.Add(new Thread(threadStarts[i])); } // Start all threads. for (int i = 0; i < numOfThreads; i++) { threads[i].Start(); } // Find better way to wait for all threads to finish. Join ties up threads. bool stillBusy = true; while (stillBusy) { stillBusy = false; for (int i = 0; i < numOfThreads; i++) { if (threads[i].IsAlive) { stillBusy = true; Thread.Sleep(1); break; } } } // Add up all puzzles. ulong totalLegalPuzzles = 0; for (int i = 0; i < numOfThreads; i++) { totalLegalPuzzles += nurikabes[i].LegalPuzzles; } //Each instance of a nurikabe puzzle includes the trivial case. This subtracts each extra trivial case and adds one back in. return(totalLegalPuzzles - (ulong)numOfThreads + 1); }