diff --git a/CodeReviews.Console.Calculator.sln b/CodeReviews.Console.Calculator.sln new file mode 100644 index 00000000..6de92dc7 --- /dev/null +++ b/CodeReviews.Console.Calculator.sln @@ -0,0 +1,56 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{827E0CD3-B72D-47B6-A68D-7590B98EB39B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Calculator", "src\Calculator.csproj", "{23269A6C-8755-4F73-98C1-FEB1E64BE94C}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "lib", "lib", "{3A8DF596-E814-FECC-DD4B-D8EF8AAC1A0D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CalculatorLibrary", "lib\CalculatorLibrary.csproj", "{D2B87518-0CC2-4DF9-B257-5FBBFB7BE093}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {23269A6C-8755-4F73-98C1-FEB1E64BE94C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {23269A6C-8755-4F73-98C1-FEB1E64BE94C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {23269A6C-8755-4F73-98C1-FEB1E64BE94C}.Debug|x64.ActiveCfg = Debug|Any CPU + {23269A6C-8755-4F73-98C1-FEB1E64BE94C}.Debug|x64.Build.0 = Debug|Any CPU + {23269A6C-8755-4F73-98C1-FEB1E64BE94C}.Debug|x86.ActiveCfg = Debug|Any CPU + {23269A6C-8755-4F73-98C1-FEB1E64BE94C}.Debug|x86.Build.0 = Debug|Any CPU + {23269A6C-8755-4F73-98C1-FEB1E64BE94C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {23269A6C-8755-4F73-98C1-FEB1E64BE94C}.Release|Any CPU.Build.0 = Release|Any CPU + {23269A6C-8755-4F73-98C1-FEB1E64BE94C}.Release|x64.ActiveCfg = Release|Any CPU + {23269A6C-8755-4F73-98C1-FEB1E64BE94C}.Release|x64.Build.0 = Release|Any CPU + {23269A6C-8755-4F73-98C1-FEB1E64BE94C}.Release|x86.ActiveCfg = Release|Any CPU + {23269A6C-8755-4F73-98C1-FEB1E64BE94C}.Release|x86.Build.0 = Release|Any CPU + {D2B87518-0CC2-4DF9-B257-5FBBFB7BE093}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D2B87518-0CC2-4DF9-B257-5FBBFB7BE093}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D2B87518-0CC2-4DF9-B257-5FBBFB7BE093}.Debug|x64.ActiveCfg = Debug|Any CPU + {D2B87518-0CC2-4DF9-B257-5FBBFB7BE093}.Debug|x64.Build.0 = Debug|Any CPU + {D2B87518-0CC2-4DF9-B257-5FBBFB7BE093}.Debug|x86.ActiveCfg = Debug|Any CPU + {D2B87518-0CC2-4DF9-B257-5FBBFB7BE093}.Debug|x86.Build.0 = Debug|Any CPU + {D2B87518-0CC2-4DF9-B257-5FBBFB7BE093}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D2B87518-0CC2-4DF9-B257-5FBBFB7BE093}.Release|Any CPU.Build.0 = Release|Any CPU + {D2B87518-0CC2-4DF9-B257-5FBBFB7BE093}.Release|x64.ActiveCfg = Release|Any CPU + {D2B87518-0CC2-4DF9-B257-5FBBFB7BE093}.Release|x64.Build.0 = Release|Any CPU + {D2B87518-0CC2-4DF9-B257-5FBBFB7BE093}.Release|x86.ActiveCfg = Release|Any CPU + {D2B87518-0CC2-4DF9-B257-5FBBFB7BE093}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {23269A6C-8755-4F73-98C1-FEB1E64BE94C} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B} + {D2B87518-0CC2-4DF9-B257-5FBBFB7BE093} = {3A8DF596-E814-FECC-DD4B-D8EF8AAC1A0D} + EndGlobalSection +EndGlobal diff --git a/calculator.qua9k.csproj b/calculator.qua9k.csproj new file mode 100644 index 00000000..dfb40caa --- /dev/null +++ b/calculator.qua9k.csproj @@ -0,0 +1,10 @@ + + + + Exe + net10.0 + enable + enable + + + diff --git a/src/Calculator.cs b/src/Calculator.cs new file mode 100644 index 00000000..69714ef9 --- /dev/null +++ b/src/Calculator.cs @@ -0,0 +1,112 @@ +using System.Text; +using System.Text.Json; + +namespace calculator.qua9k.lib; + +public class Calculator +{ + private readonly Utf8JsonWriter _writer; + private readonly List _history = []; + + public Calculator() + { + var logFile = File.OpenWrite(path: "calculator_log.json"); + _writer = new Utf8JsonWriter(logFile); + _writer.WriteStartObject(); + _writer.WritePropertyName("Operations"); + _writer.WriteStartArray(); + } + + public double DoOperation(double num1, double num2, string op) + { + var result = double.NaN; + StringBuilder operation = new(); + + _writer.WriteStartObject(); + _writer.WritePropertyName("Operand1"); + _writer.WriteNumberValue(num1); + _writer.WritePropertyName("Operand2"); + _writer.WriteNumberValue(num2); + _writer.WritePropertyName("Operation"); + + switch (op) + { + case "+": + result = num1 + num2; + _writer.WriteStringValue("Add"); + break; + case "-": + result = num1 - num2; + _writer.WriteStringValue("Subtract"); + break; + case "*": + result = num1 * num2; + _writer.WriteStringValue("Multiply"); + break; + case "/": + if (num2 != 0) + { + result = num1 / num2; + } + _writer.WriteStringValue("Divide"); + break; + case "^": + result = Math.Pow(num1, num2); + _writer.WriteStringValue("Exponentiate"); + break; + case "log": + result = Math.Log(num1, num2); + _writer.WriteStringValue("Logarithm"); + break; + } + result = Math.Round(result, 2); + _writer.WritePropertyName("Result"); + _writer.WriteNumberValue(result); + _writer.WriteEndObject(); + + operation.Append($"{num1} {op} {num2} = {result}"); + _history.Add(operation.ToString()); + + return result; + } + + public void PrintHistory() + { + if (_history.Count <= 0) + { + Console.WriteLine("The history is empty."); + return; + } + + Console.WriteLine( + """ + History + + """ + ); + + for (var i = 0; i < _history.Count; i++) + { + Console.WriteLine($"{i}: {_history[i]}"); + } + } + + public void ClearHistory() + { + Console.WriteLine( + """ + History cleared. + + """ + ); + _history.Clear(); + } + + public void Finish() + { + _writer.WriteEndArray(); + _writer.WriteEndObject(); + _writer.Flush(); + _writer.Dispose(); + } +} \ No newline at end of file diff --git a/src/Calculator.csproj b/src/Calculator.csproj new file mode 100644 index 00000000..166dab57 --- /dev/null +++ b/src/Calculator.csproj @@ -0,0 +1,14 @@ + + + + + + + + Exe + net10.0 + enable + enable + + + diff --git a/src/Program.cs b/src/Program.cs new file mode 100644 index 00000000..71eee411 --- /dev/null +++ b/src/Program.cs @@ -0,0 +1,112 @@ +using calculator.qua9k.lib; + +namespace calculator.qua9k; + +internal class Program +{ + private static void Main() + { + Calculator calc = new(); + Dictionary operatorMap = new() + { + { "+", "Add" }, + { "-", "Subtract" }, + { "*", "Multiply" }, + { "/", "Divide" }, + { "^", "Exponentiate" }, + { "log", "Logarithm" } + }; + + var validOperand1 = double.MinValue; + var postCalcChoice = ""; + var endApp = false; + + while (!endApp) + { + Console.Clear(); + UserInterface.PrintHeader(); + + if (postCalcChoice == "p") + { + Console.WriteLine($"Previous result: {validOperand1}"); + } + else + { + Console.Write("Enter the first operand: "); + GetOperand(out validOperand1); + } + + Console.Write("Enter the second operand: "); + GetOperand(out var validOperand2); + + Console.WriteLine("Choose an operator:"); + UserInterface.PrintOperations(operatorMap); + + Console.Write("Your option? "); + var op = Console.ReadLine(); + var result = double.MinValue; + + if (op == null || !operatorMap.ContainsKey(op)) + Console.WriteLine("Error: Unrecognized input."); + else + try + { + result = calc.DoOperation(validOperand1, validOperand2, op); + + if (double.IsNaN(result)) + Console.WriteLine("This operation will result in a mathematical error.\n"); + else + Console.WriteLine("Your result: {0:0.##}\n", result); + } + catch (Exception e) + { + Console.WriteLine("An exception occurred.\n - Details: " + e.Message); + } + + UserInterface.Pause(); + UserInterface.PrintMenuOptions(); + + postCalcChoice = Console.ReadLine(); + + while (postCalcChoice is "h" or "d") + { + Console.Clear(); + UserInterface.PrintHeader(); + + if (postCalcChoice == "h") + calc.PrintHistory(); + else + calc.ClearHistory(); + + UserInterface.Pause(); + UserInterface.PrintMenuOptions(); + + postCalcChoice = Console.ReadLine(); + } + + switch (postCalcChoice) + { + case "p": + validOperand1 = result; + break; + case "n": + Console.WriteLine("Goodbye!"); + endApp = true; + break; + } + } + + calc.Finish(); + } + + private static void GetOperand(out double validNum) + { + var userInput = Console.ReadLine(); + + while (!double.TryParse(userInput, out validNum)) + { + Console.Write("Invalid input. Enter a numeric value: "); + userInput = Console.ReadLine(); + } + } +} \ No newline at end of file diff --git a/src/UserInterface.cs b/src/UserInterface.cs new file mode 100644 index 00000000..1dd6a369 --- /dev/null +++ b/src/UserInterface.cs @@ -0,0 +1,36 @@ +namespace calculator.qua9k; + +internal static class UserInterface +{ + public static void PrintOperations(Dictionary operatorMap) + { + foreach (var kvp in operatorMap) Console.WriteLine($" {kvp.Key} : {kvp.Value}"); + } + + public static void Pause() + { + Console.WriteLine(); + Console.Write("Press any key to continue."); + Console.ReadKey(); + } + + public static void PrintMenuOptions() + { + Console.Write( + """ + - 'n' + Enter : close the app. + - 'p' + Enter : use the previous result as the first operand. + - 'h' + Enter : view operation history. + - 'd' + Enter : delete operation history. + - Any other key to perform a new calculation. + + """ + ); + } + + public static void PrintHeader() + { + Console.WriteLine("Console Calculator in C#\r"); + Console.WriteLine("------------------------\n"); + } +} \ No newline at end of file diff --git a/src/calculator_log.json b/src/calculator_log.json new file mode 100644 index 00000000..ac3fa14c --- /dev/null +++ b/src/calculator_log.json @@ -0,0 +1 @@ +{"Operations":[{"Operand1":3,"Operand2":3,"Operation":"Add","Result":6}]} \ No newline at end of file