From d56a4cbb64f7d5f0378c21b80ebcf2c31fe3bdde Mon Sep 17 00:00:00 2001 From: cc0322 <36272241+cc0322@users.noreply.github.com> Date: Thu, 8 Feb 2018 23:54:23 -0500 Subject: [PATCH] Add files --- App.config | 6 ++ AssemblyInfo.cs | 36 ++++++++ NewProjectCC.csproj | 52 +++++++++++ Program.cs | 208 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 302 insertions(+) create mode 100644 App.config create mode 100644 AssemblyInfo.cs create mode 100644 NewProjectCC.csproj create mode 100644 Program.cs diff --git a/App.config b/App.config new file mode 100644 index 0000000..d740e88 --- /dev/null +++ b/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/AssemblyInfo.cs b/AssemblyInfo.cs new file mode 100644 index 0000000..dc13a39 --- /dev/null +++ b/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("NewProjectCC")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("NewProjectCC")] +[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("11e7112d-322a-43d8-ba9e-1616f0cd7fcf")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/NewProjectCC.csproj b/NewProjectCC.csproj new file mode 100644 index 0000000..21c0939 --- /dev/null +++ b/NewProjectCC.csproj @@ -0,0 +1,52 @@ + + + + + Debug + AnyCPU + {11E7112D-322A-43D8-BA9E-1616F0CD7FCF} + Exe + NewProjectCC + NewProjectCC + v4.5.2 + 512 + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..2e07dd1 --- /dev/null +++ b/Program.cs @@ -0,0 +1,208 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace NewProjectCC +{ + /// Thinking of a large system, I'd like to save all the output from one key to the other to a hashtable. This will save the time complexity since we don't need to + /// process any logic from key to key but only get value from hashtable. + /// If the size of the input file is big, and we have enough resource, I believe we can do a divide and conquer to read different lines from the input file and process it at the same time. + /// I didn't implement devide and conquer today. But do please let me know if you'd like me to implement it that way. Thank you so much! + class Program + { + //Keyboard characters except space + const string KeyBoard = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; + //Hashtable which stores the preprocessed output from key to another key on the keyboard + public static Hashtable keyToKeyMatrix; + + static void Main(string[] args) + { + //Generate the hashtable from pre-process to get the output key from one key to another on the keyboard + PreProcess(); + //Get input search term by line + var input = ParseArgument(); + //For each line of the search term, process the result, and write it down to the console. + if (input != null) + { + Console.WriteLine("The output is: "); + Console.WriteLine("---"); + foreach (var r in GetResult(input)) + { + //If it's the message for invalid input, don't add comma between each character. + if (r.Contains("Invalid input detected in this term")) + Console.WriteLine(r); + else + Console.WriteLine(string.Join(",", r.ToCharArray())); + } + } + //To keep console open until press a key + Console.WriteLine("---"); + Console.WriteLine("Press any key to close this window..."); + Console.Read(); + } + + /// + /// Get result by matching the characters read from the input file and write the path to the console + /// + /// A string list, each line contains a sarch term (one line from input file) + /// string array for the path output + private static string[] GetResult(List input) + { + var result = new string[input.Count]; + int resultIndex = 0; + //Read by term + foreach (var line in input) + { + var output = string.Empty; + //If the line is empty, there's no output. + if (!string.IsNullOrEmpty(line)) + { + //Define start point A + var preChar = 'A'; + for (int i = 0; i < line.Length; i++) + { + //If the input character is not valid (not in the keyboard) + if (!(line[i].Equals(' ') || KeyBoard.Contains(line[i]))) + { + output = (string.Format("Invalid input detected in this term: {0}", line[i])); + break; + } + + //Get the correct output path from current character and previous character + if (line[i].Equals(' ')) + output += "S"; + else if (line[i].Equals(preChar)) + output += "#"; + else + { + var index = string.Format("{0}{1}", preChar, line[i]); + output += keyToKeyMatrix[index].ToString(); + preChar = line[i]; + } + } + } + //Add the output per line to the result string array. + result[resultIndex++] = output; + } + + return result; + } + + /// + /// Parse argument, read file name from console, and read the file + /// + /// String list by reading file by line. + private static List ParseArgument() + { + var inputPerLine = new List(); + var line = string.Empty; + + //Read file name + Console.WriteLine("Please specify your input file below: "); + try + { + var inputFileName = Console.ReadLine(); + if (inputFileName != null) + { + //Read file using streamreader + StreamReader file = new StreamReader(inputFileName); + //Read line + while ((line = file.ReadLine()) != null) + { + inputPerLine.Add(line); + } + } + } + catch (Exception) + { + //Catch exception while reading file, write it to console + Console.WriteLine("Error occurred during reading the file, please try again."); + return null; + } + + //If the input file is empty, return a console message. + if (inputPerLine.Count == 0) + { + Console.WriteLine("Empty input file detected."); + return null; + } + + return inputPerLine; + } + + /// + /// This preprocess will generate a hashtable and write this hashtable to a file, so this doesn't need to be run unless the file is missing. + /// For each element in this hashtable, the key is currentKey to NextKey when these two keys are different. For example, "AB" means from A to B on the given keyboard; + /// the value is the path through the onscreen keyboard (output). For example, the value for "AB" is "R#" + /// + /// Hashtable with path from one key to the other + private static Hashtable PreProcess() + { + keyToKeyMatrix = new Hashtable(); + + //Convert the keyboard string to ASCII chars + var charsASCII = Encoding.ASCII.GetBytes(KeyBoard.ToCharArray()); + + //Process the ASCII char array, so that A is 0, and every other cahracter is the distance to A, including 1-0 which shows on the onscreen keyboard too. + for (int n = 0; n < charsASCII.Length; n++) + { + //This handles number 0 + if (n == charsASCII.Length - 1) + charsASCII[n] -= 13; //ASCII for 0 = 48, in the keyboard string, 0's index is 35. So 48-35=13 + //This handles number 1-9 + else if (n >= charsASCII.Length - 10) + charsASCII[n] -= 23; //ASCII for 1 = 49, in the keyboard string, 1's index is 26. So 49-26=23 + else + charsASCII[n] -= 65; //ASCII for A = 65 + } + + //These loops calcultes the real path from one key to another from the oncreen keyboard, and add the key and the value to the hashtable + for (int i = 0; i < charsASCII.Length; i++) + { + //Since the paths are always opposite between one key to another, only loop the the ones after charsASCII[i] is enough + for (int j = i + 1; j < charsASCII.Length; j++) + { + var outputPattern = string.Empty; + var outputPatternReverse = string.Empty; + + //Think the onscreen keyboard as a matrix with x and y coordinate, the position for the two keys are presents as in positioni and positionj + var positioni = new KeyValuePair(charsASCII[i] % 6, charsASCII[i] / 6); + var positionj = new KeyValuePair(charsASCII[j] % 6, charsASCII[j] / 6); + + //Get the horizonal distance + var horizonalDistance = positionj.Key - positioni.Key; + //If the distance is greater than 0, then from key i to key j, we need to move right, and from key j to key i , we need to move left. Vise Versa. + for (int a = 0; a < Math.Abs(horizonalDistance); a++) + { + outputPattern += "L"; + outputPatternReverse += "R"; + } + if (horizonalDistance > 0) + { + var temp = outputPattern; + outputPattern = outputPatternReverse; + outputPatternReverse = temp; + } + + //Since key j is always after key i , the vertical distance is always greater or equal than 0 + for (int b = 0; b < (positionj.Value - positioni.Value); b++) + { + outputPattern += "D"; + outputPatternReverse += "U"; + } + + //Get char from the keyboard string + var chars = KeyBoard.ToCharArray(); + + //Add "" as key, the path with selected key # as value + keyToKeyMatrix.Add(string.Format("{0}{1}", chars[i], chars[j]), string.Format("{0}#", outputPattern)); + keyToKeyMatrix.Add(string.Format("{0}{1}", chars[j], chars[i]), string.Format("{0}#", outputPatternReverse)); + } + } + return keyToKeyMatrix; + } + } +}