}//GenerateStringSimple2_r //REF tex converted from recursion (above) to using a stack object (recursion just uses program stack anyway). static void GenerateStringSimple_Stack(List <string>[] allWordsList) { Stack <RecurseStep> stack = new Stack <RecurseStep>(); RecurseStep startState = new RecurseStep(); startState.currentDepth = 0; startState.currentWordListIndex = 0; startState.currentString = ""; stack.Push(startState); while (stack.Count > 0) { RecurseStep recurseStep = stack.Pop(); if (recurseStep.currentDepth == allWordsList.Length) { Console.WriteLine(recurseStep.currentString); } else { List <string> wordList = allWordsList[recurseStep.currentDepth]; for (int wordListIndex = 0; wordListIndex < wordList.Count; wordListIndex++) { RecurseStep nextState = new RecurseStep(); nextState.currentDepth = recurseStep.currentDepth + 1; nextState.currentWordListIndex = wordListIndex; nextState.currentString = recurseStep.currentString + wordList[wordListIndex]; stack.Push(nextState); } } } }//GenerateStringSimple_Stack
}//GenerateStringSimple_r //REF tex evolution of above with state moved into struct static void GenerateStringSimple2_r(List <string>[] allWordsList, RecurseStep state) { if (state.currentDepth == allWordsList.Length) { Console.WriteLine(state.currentString); return; } else { List <string> wordList = allWordsList[state.currentDepth]; for (int wordListIndex = 0; wordListIndex < wordList.Count; wordListIndex++) { RecurseStep nextState = new RecurseStep(); nextState.currentDepth = state.currentDepth + 1; nextState.currentWordListIndex = wordListIndex; nextState.currentString = state.currentString + wordList[wordListIndex]; GenerateStringSimple2_r(allWordsList, nextState); } } }//GenerateStringSimple2_r
private static void SimpleTests(List <string>[] allWordsLists) { Console.WriteLine("!!!!SimpleTests"); //tex filling out all variables to get concanical serialization. GenConfig config = new GenConfig(); config.batch_size = 1; config.words_base_path = @"D:\GitHub\BruteGen\Examples\3x3 - test hashes"; config.words_paths.Add("wordA"); config.words_paths.Add("wordB"); config.words_paths.Add("wordC"); config.output_path = @"D:\GitHub\BruteGen\Examples\Examples Output"; config.word_variations_all.Add("dont_add_original"); config.word_variations_all.Add("all_upper"); config.word_variations_all.Add("all_lower"); config.word_variations_all.Add("capitalized"); config.word_variations_all.Add("blank_optional"); config.test_hashes_path = @"D:\GitHub\BruteGen\Examples\3x3 - test hashes\StrCode32Hashes"; config.test_hashes_func = "StrCode32"; JsonSerializerSettings serializeSettings = new JsonSerializerSettings(); serializeSettings.Formatting = Formatting.Indented; string jsonStringOut = JsonConvert.SerializeObject(config, serializeSettings); string jsonOutPath = @"D:\GitHub\BruteGen\full-config.json"; File.WriteAllText(jsonOutPath, jsonStringOut); RecurseStep startStateS = new RecurseStep(); startStateS.currentDepth = 0; startStateS.currentWordListIndex = 0; startStateS.currentString = ""; GenerateStringSimple2_r(allWordsLists, startStateS); GenerateStringSimple_Stack(allWordsLists); } //SimpleTests
}//BatchTest //REF CULL Old stack based static void GenerateStringsStack(Stack <RecurseStep> resumeState, List <string>[] allWordsLists, HashInfo hashInfo, int batchSize, bool testOnBatch, string resumeStatePath, string stringsOutPath) { var totalStopwatch = new System.Diagnostics.Stopwatch(); totalStopwatch.Start(); int loopCount = 0; bool isResume = resumeState != null; List <string> batch = new List <string>(); List <int> recurseState = new List <int>(new int[allWordsLists.Length]);//tex purely for user to get an idea of how it's progressing //tex using a custom stack instead of the usual nested loops for generating strings, this allows the whole state to be saved of so program can be quit and resumed later. //tex initialize stack Stack <RecurseStep> stack = new Stack <RecurseStep>(); if (resumeState == null) { RecurseStep startState = new RecurseStep(); startState.currentDepth = 0; startState.currentWordListIndex = 0; startState.currentString = ""; stack.Push(startState); } else { // tex more stack order shenanigans, dont ask me why while (resumeState.Count > 0) { stack.Push(resumeState.Pop()); } }//init stack if (!isResume) { Console.WriteLine("Starting GenerateStrings"); } else { Console.WriteLine("Resuming GenerateStrings"); } using (StreamWriter sw = new StreamWriter(stringsOutPath, isResume)) {//tex StreamWriter append = isResume while (stack.Count > 0) { loopCount++; RecurseStep state = stack.Pop(); //tex you can output currentString here if you want to catch each stage of generation instead of just complete string below //but I currently prefer just having empty strings in the word lists for per word control if (state.currentDepth == allWordsLists.Length) //tex generated whole test-string { string currentString = state.currentString; if (!testOnBatch) { //tex if no inputhashes then we just write every generated string if (hashInfo.inputHashes == null) { sw.WriteLine(currentString); } else { var hash = hashInfo.HashFunc(currentString); if (hashInfo.inputHashes.Contains(hash)) { sw.WriteLine(currentString); } } }//testOnBatch batch.Add(currentString); //tex write/flush current strings and write resume_state if (batch.Count >= batchSize) { //tex write resume state string jsonStringOut = JsonConvert.SerializeObject(stack); File.WriteAllText(resumeStatePath, jsonStringOut); //tex give user feedback string rs = ""; foreach (int wordIndex in recurseState) { rs += " " + wordIndex; } Console.WriteLine(rs + " : " + currentString);//TODO: order is shifted by one in comparison to wordcounts output earlier in the program, figure out what's up. //tex test batch if (testOnBatch) { BatchTest(hashInfo, batch, sw); }//testOnBatch //tex clear batch and flush/write matches streamwriter batch = new List <string>(); sw.Flush(); }//batchSize } else //tex recurse { recurseState[state.currentDepth] = state.currentWordListIndex; List <string> wordList = allWordsLists[state.currentDepth]; //tex due to stack the order is actually reversed compared to recursion // for (int wordListIndex = 0; wordListIndex < wordList.Count; wordListIndex++) for (int wordListIndex = wordList.Count - 1; wordListIndex >= 0; wordListIndex--) { //tex this is where we'd normally recursively call the generation function with the current state of the partially generated string //instead we're just seting up our stack of that state, for the next loop RecurseStep nextState = new RecurseStep(); nextState.currentDepth = state.currentDepth + 1; nextState.currentWordListIndex = wordListIndex; nextState.currentString = state.currentString + wordList[wordListIndex]; stack.Push(nextState); } } //if generated whole word } //while stack //tex need to process incomplete batch if (batch.Count > 0) { //tex test batch if (testOnBatch) { BatchTest(hashInfo, batch, sw); }//testOnBatch //tex clear batch and flush/write matches streamwriter batch = new List <string>(); sw.Flush(); } //batch.Count > 0 } //using sw totalStopwatch.Stop(); var timeSpan = totalStopwatch.Elapsed; Console.WriteLine($"GenerateStrings completed in {timeSpan.Hours}:{timeSpan.Minutes}:{timeSpan.Seconds}:{timeSpan.Milliseconds}"); Console.WriteLine($"LoopCount: {loopCount}"); }//GenerateStrings