/// <summary> /// Recursively decodes the current <see cref="MorseSequence"/> beginning from the specified <paramref name="startIndex"/> /// </summary> /// <param name="currentDecodedContext">If <paramref name="startIndex"/> is not 0, this may contain decoding information /// from previous positions.</param> /// <param name="startIndex">The position to start decoding from in the <see cref="MorseSequence"/></param> /// <param name="currentDecodedMessage">Full string contain the state of the <see cref="MorseSequence"/> decoding till /// the <paramref name="startIndex"/></param> /// <returns></returns> public async Task DecodeMorseSequenceAsync( KeyValuePair <string, string> currentDecodedContext = default, int startIndex = default, string currentDecodedMessage = "") { if (startIndex > this.MorseSequence.Length) { await Console.Error.WriteLineAsync($"Index: {startIndex} has exceeded morse length: {this.MorseSequence.Length}"); return; } if (currentDecodedContext.Key == null || currentDecodedContext.Value == null) { currentDecodedContext = MorseDecoder.GetEmptyDecodedContext(); } string cacheHash = currentDecodedMessage + startIndex + currentDecodedContext.Value; if (this.searchStateCache.Contains(cacheHash)) { return; } this.searchStateCache.Add(cacheHash); //message is fully decoded when search reaches the end of the entire morse sequence //and no sequence is currently being decoded if (startIndex == this.MorseSequence.Length && currentDecodedContext.Key.Length == 0) { this.decodedMessages.Add(currentDecodedMessage.Trim()); await Console.Error.WriteLineAsync($"Adding decoded message: {currentDecodedMessage}"); return; } string morseToDecode = this.MorseSequence.Substring( startIndex, Math.Min(MorseDecoder.MorseCharacterMaxLength, this.MorseSequence.Length - startIndex)); ISet <KeyValuePair <string, string> > decodedSequences = this.DecodeMorse(morseToDecode, currentDecodedContext); foreach (KeyValuePair <string, string> newDecodedContext in decodedSequences) { int newIndex = newDecodedContext.Key.Length - currentDecodedContext.Key.Length + startIndex; await this.DecodeMorseSequenceAsync(newDecodedContext, newIndex, currentDecodedMessage); if (!this.CheckWordExists(newDecodedContext.Value)) { continue; } string newPreceedingMessage = currentDecodedMessage + newDecodedContext.Value + " "; await Console.Error.WriteLineAsync($"New sequence discovered: {newPreceedingMessage}\n"); //clear decoded context to start attempting new words await this.DecodeMorseSequenceAsync(MorseDecoder.GetEmptyDecodedContext(), newIndex, newPreceedingMessage); } }
/// <summary> /// Returns a list of possible character combinations from the given morse input. /// /// The input morse should have a limit not greater than <see cref="MorseCharacterMaxLength"/>. /// This limit is not enforced but if violated, could result in unexpected behaviours. /// </summary> /// <param name="morse">The morse to decode</param> /// <param name="currentDecodedContext">Possible pre-decoded sequence that the new outputs will be appended to,</param> public ISet <KeyValuePair <string, string> > DecodeMorse(string morse, KeyValuePair <string, string> currentDecodedContext = default) { if (string.IsNullOrEmpty(morse)) { return(new HashSet <KeyValuePair <string, string> >()); } if (currentDecodedContext.Key == null || currentDecodedContext.Value == null) { currentDecodedContext = MorseDecoder.GetEmptyDecodedContext(); } ISet <KeyValuePair <string, string> > decodedSequences = new HashSet <KeyValuePair <string, string> >(); //Try all combinations to find decoded messages foreach (string decodeCombination in MorseDecoder.DecodingCombinations) { this.DecodeMorseWithCombination(morse, decodeCombination, currentDecodedContext, decodedSequences); } return(decodedSequences); }