From d6db36ee915b6c8c4a9fb56e8e204ad8364fe601 Mon Sep 17 00:00:00 2001 From: Ivan Garzon Date: Wed, 2 Sep 2026 15:46:04 -0400 Subject: [PATCH 01/10] Initial Console project setup --- Calculator.ivangar/Calculator.ivangar.slnx | 3 +++ .../Calculator.ivangar/Calculator.ivangar.csproj | 10 ++++++++++ Calculator.ivangar/Calculator.ivangar/Program.cs | 1 + 3 files changed, 14 insertions(+) create mode 100644 Calculator.ivangar/Calculator.ivangar.slnx create mode 100644 Calculator.ivangar/Calculator.ivangar/Calculator.ivangar.csproj create mode 100644 Calculator.ivangar/Calculator.ivangar/Program.cs diff --git a/Calculator.ivangar/Calculator.ivangar.slnx b/Calculator.ivangar/Calculator.ivangar.slnx new file mode 100644 index 00000000..ea3a809b --- /dev/null +++ b/Calculator.ivangar/Calculator.ivangar.slnx @@ -0,0 +1,3 @@ + + + diff --git a/Calculator.ivangar/Calculator.ivangar/Calculator.ivangar.csproj b/Calculator.ivangar/Calculator.ivangar/Calculator.ivangar.csproj new file mode 100644 index 00000000..ed9781c2 --- /dev/null +++ b/Calculator.ivangar/Calculator.ivangar/Calculator.ivangar.csproj @@ -0,0 +1,10 @@ + + + + Exe + net10.0 + enable + enable + + + diff --git a/Calculator.ivangar/Calculator.ivangar/Program.cs b/Calculator.ivangar/Calculator.ivangar/Program.cs new file mode 100644 index 00000000..1bc52a60 --- /dev/null +++ b/Calculator.ivangar/Calculator.ivangar/Program.cs @@ -0,0 +1 @@ +Console.WriteLine("Hello, World!"); From b1f2788255d9b56e8b326c566b87508780a09e61 Mon Sep 17 00:00:00 2001 From: Ivan Garzon Date: Wed, 2 Sep 2026 16:32:25 -0400 Subject: [PATCH 02/10] Added Calculator console app - part 1 --- .../Calculator.ivangar/Program.cs | 117 +++++++++++++++++- 1 file changed, 116 insertions(+), 1 deletion(-) diff --git a/Calculator.ivangar/Calculator.ivangar/Program.cs b/Calculator.ivangar/Calculator.ivangar/Program.cs index 1bc52a60..f8100411 100644 --- a/Calculator.ivangar/Calculator.ivangar/Program.cs +++ b/Calculator.ivangar/Calculator.ivangar/Program.cs @@ -1 +1,116 @@ -Console.WriteLine("Hello, World!"); +using System.Text.RegularExpressions; + +class Calculator +{ + public static double DoOperation(double num1, double num2, string op) + { + double result = double.NaN; // Default value is "not-a-number" if an operation, such as division, could result in an error. + + // Use a switch statement to do the math. + switch (op) + { + case "a": + result = num1 + num2; + break; + case "s": + result = num1 - num2; + break; + case "m": + result = num1 * num2; + break; + case "d": + // Ask the user to enter a non-zero divisor. + if (num2 != 0) + { + result = num1 / num2; + } + break; + // Return text for an incorrect option entry. + default: + break; + } + return result; + } +} + +class Program +{ + static void Main(string[] args) + { + bool endApp = false; + // Display title as the C# console calculator app. + Console.WriteLine("Console Calculator in C#\r"); + Console.WriteLine("------------------------\n"); + + while (!endApp) + { + // Declare variables and set to empty. + // Use Nullable types (with ?) to match type of System.Console.ReadLine + string? numInput1 = ""; + string? numInput2 = ""; + double result = 0; + + // Ask the user to type the first number. + Console.Write("Type a number, and then press Enter: "); + numInput1 = Console.ReadLine(); + + double cleanNum1 = 0; + while (!double.TryParse(numInput1, out cleanNum1)) + { + Console.Write("This is not valid input. Please enter a numeric value: "); + numInput1 = Console.ReadLine(); + } + + // Ask the user to type the second number. + Console.Write("Type another number, and then press Enter: "); + numInput2 = Console.ReadLine(); + + double cleanNum2 = 0; + while (!double.TryParse(numInput2, out cleanNum2)) + { + Console.Write("This is not valid input. Please enter a numeric value: "); + numInput2 = Console.ReadLine(); + } + + // Ask the user to choose an operator. + Console.WriteLine("Choose an operator from the following list:"); + Console.WriteLine("\ta - Add"); + Console.WriteLine("\ts - Subtract"); + Console.WriteLine("\tm - Multiply"); + Console.WriteLine("\td - Divide"); + Console.Write("Your option? "); + + string? op = Console.ReadLine(); + + // Validate input is not null, and matches the pattern + if (op == null || !Regex.IsMatch(op, "^(a|s|m|d)$")) + { + Console.WriteLine("Error: Unrecognized input."); + } + else + { + try + { + result = Calculator.DoOperation(cleanNum1, cleanNum2, 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("Oh no! An exception occurred trying to do the math.\n - Details: " + e.Message); + } + } + Console.WriteLine("------------------------\n"); + + // Wait for the user to respond before closing. + Console.Write("Press 'n' and Enter to close the app, or press any other key and Enter to continue: "); + if (Console.ReadLine() == "n") endApp = true; + + Console.WriteLine("\n"); // Friendly linespacing. + } + return; + } +} \ No newline at end of file From e812adea233428f72930f3019c2cf716f21f261b Mon Sep 17 00:00:00 2001 From: Ivan Garzon Date: Mon, 14 Sep 2026 17:35:06 -0400 Subject: [PATCH 03/10] Calculator console app - part 2 --- Calculator.ivangar/Calculator.ivangar.slnx | 1 + .../Calculator.ivangar.csproj | 4 ++ .../Calculator.ivangar/Program.cs | 43 +++-------- .../CalculatorLibrary/CalculatorLibrary.cs | 72 +++++++++++++++++++ .../CalculatorLibrary.csproj | 13 ++++ 5 files changed, 98 insertions(+), 35 deletions(-) create mode 100644 Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.cs create mode 100644 Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.csproj diff --git a/Calculator.ivangar/Calculator.ivangar.slnx b/Calculator.ivangar/Calculator.ivangar.slnx index ea3a809b..34bb6a99 100644 --- a/Calculator.ivangar/Calculator.ivangar.slnx +++ b/Calculator.ivangar/Calculator.ivangar.slnx @@ -1,3 +1,4 @@ + diff --git a/Calculator.ivangar/Calculator.ivangar/Calculator.ivangar.csproj b/Calculator.ivangar/Calculator.ivangar/Calculator.ivangar.csproj index ed9781c2..8acb7da5 100644 --- a/Calculator.ivangar/Calculator.ivangar/Calculator.ivangar.csproj +++ b/Calculator.ivangar/Calculator.ivangar/Calculator.ivangar.csproj @@ -7,4 +7,8 @@ enable + + + + diff --git a/Calculator.ivangar/Calculator.ivangar/Program.cs b/Calculator.ivangar/Calculator.ivangar/Program.cs index f8100411..b3351ffa 100644 --- a/Calculator.ivangar/Calculator.ivangar/Program.cs +++ b/Calculator.ivangar/Calculator.ivangar/Program.cs @@ -1,37 +1,5 @@ -using System.Text.RegularExpressions; - -class Calculator -{ - public static double DoOperation(double num1, double num2, string op) - { - double result = double.NaN; // Default value is "not-a-number" if an operation, such as division, could result in an error. - - // Use a switch statement to do the math. - switch (op) - { - case "a": - result = num1 + num2; - break; - case "s": - result = num1 - num2; - break; - case "m": - result = num1 * num2; - break; - case "d": - // Ask the user to enter a non-zero divisor. - if (num2 != 0) - { - result = num1 / num2; - } - break; - // Return text for an incorrect option entry. - default: - break; - } - return result; - } -} +using CalculatorLibrary; +using System.Text.RegularExpressions; class Program { @@ -42,6 +10,8 @@ static void Main(string[] args) Console.WriteLine("Console Calculator in C#\r"); Console.WriteLine("------------------------\n"); + var calculator = new Calculator(); + while (!endApp) { // Declare variables and set to empty. @@ -91,7 +61,7 @@ static void Main(string[] args) { try { - result = Calculator.DoOperation(cleanNum1, cleanNum2, op); + result = calculator.DoOperation(cleanNum1, cleanNum2, op); if (double.IsNaN(result)) { Console.WriteLine("This operation will result in a mathematical error.\n"); @@ -111,6 +81,9 @@ static void Main(string[] args) Console.WriteLine("\n"); // Friendly linespacing. } + + calculator.Finish(); + return; } } \ No newline at end of file diff --git a/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.cs b/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.cs new file mode 100644 index 00000000..dd4d7b41 --- /dev/null +++ b/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.cs @@ -0,0 +1,72 @@ +using Newtonsoft.Json; + +namespace CalculatorLibrary +{ + public class Calculator + { + JsonWriter writer; + + public Calculator() + { + StreamWriter logFile = File.CreateText("calculator.json"); + logFile.AutoFlush = true; + writer = new JsonTextWriter(logFile); + writer.Formatting = Formatting.Indented; + writer.WriteStartObject(); + writer.WritePropertyName("Operations"); + writer.WriteStartArray(); + } + + public double DoOperation(double num1, double num2, string op) + { + double result = double.NaN; // Default value is "not-a-number" if an operation, such as division, could result in an error. + writer.WriteStartObject(); + writer.WritePropertyName("Operand1"); + writer.WriteValue(num1); + writer.WritePropertyName("Operand2"); + writer.WriteValue(num2); + writer.WritePropertyName("Operation"); + + // Use a switch statement to do the math. + switch (op) + { + case "a": + result = num1 + num2; + writer.WriteValue('+'); + break; + case "s": + result = num1 - num2; + writer.WriteValue('-'); + break; + case "m": + result = num1 * num2; + writer.WriteValue('*'); + break; + case "d": + // Ask the user to enter a non-zero divisor. + if (num2 != 0) + { + result = num1 / num2; + writer.WriteValue('/'); + } + break; + // Return text for an incorrect option entry. + default: + break; + } + + writer.WritePropertyName("Result"); + writer.WriteValue(result); + writer.WriteEndObject(); + + return result; + } + + public void Finish() + { + writer.WriteEndArray(); + writer.WriteEndObject(); + writer.Close(); + } + } +} diff --git a/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.csproj b/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.csproj new file mode 100644 index 00000000..22badd14 --- /dev/null +++ b/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.csproj @@ -0,0 +1,13 @@ + + + + net10.0 + enable + enable + + + + + + + From e4b244e05e9b941b41d4ca0b6f96124f491edc54 Mon Sep 17 00:00:00 2001 From: Ivan Garzon Date: Thu, 17 Sep 2026 16:45:56 -0400 Subject: [PATCH 04/10] Refactored Calendar app with menu and operation models. --- .../Calculator.ivangar/Application.cs | 110 ++++++++++++++ Calculator.ivangar/Calculator.ivangar/Menu.cs | 67 +++++++++ .../Calculator.ivangar/Program.cs | 91 +----------- .../CalculatorLibrary/CalculatorLibrary.cs | 134 ++++++++++++++++-- .../Models/Exponentiation.cs | 13 ++ .../CalculatorLibrary/Models/MathOperation.cs | 11 ++ .../CalculatorLibrary/Models/SquareRoot.cs | 12 ++ 7 files changed, 342 insertions(+), 96 deletions(-) create mode 100644 Calculator.ivangar/Calculator.ivangar/Application.cs create mode 100644 Calculator.ivangar/Calculator.ivangar/Menu.cs create mode 100644 Calculator.ivangar/CalculatorLibrary/Models/Exponentiation.cs create mode 100644 Calculator.ivangar/CalculatorLibrary/Models/MathOperation.cs create mode 100644 Calculator.ivangar/CalculatorLibrary/Models/SquareRoot.cs diff --git a/Calculator.ivangar/Calculator.ivangar/Application.cs b/Calculator.ivangar/Calculator.ivangar/Application.cs new file mode 100644 index 00000000..162923aa --- /dev/null +++ b/Calculator.ivangar/Calculator.ivangar/Application.cs @@ -0,0 +1,110 @@ +using CalculatorLibrary; + +namespace Calculator.ivangar +{ + public class Application + { + private bool EndApp = false; + private readonly CalculatorEngine Calculator = new(); + + public void Run() + { + Menu.Intro(); + + while (!EndApp) + { + // Ask the user to choose an operator. + Menu.PrintMenu(); + string? op = Console.ReadLine(); + + while (!Menu.ValidateMainOptions(op)) + { + Menu.PrintMenu(invalid: true); + op = Console.ReadLine(); + } + + switch (op!.ToLower()) + { + case "r": + SquareRootOperation(op); + break; + case "p": + PowerOperation(op); + break; + default: + BaseMathOperation(op); + break; + } + + Console.WriteLine("------------------------\n"); + + + Console.Write("Press 'n' and Enter to close the app, or press any other key and Enter to continue: "); + if (Console.ReadLine() == "n") EndApp = true; + + Console.WriteLine("\n"); + } + + Calculator.Finish(); + } + + public void BaseMathOperation(string operation) + { + double operand1 = Menu.GetOperand("Type a number, and then press Enter: "); + double operand2 = Menu.GetOperand("Type another number, and then press Enter: "); + + try + { + var result = Calculator.DoOperation(operand1, operation, operand2); + + if (double.IsNaN(result)) + Menu.PrintError("This operation will result in a mathematical error.\n"); + + else Console.WriteLine("Your result: {0:0.##}\n", result); + } + catch (Exception e) + { + Menu.PrintError("Oh no! An exception occurred trying to do the math.\n - Details: " + e.Message); + } + } + + public void SquareRootOperation(string operation) + { + var radicand = Menu.GetOperand("Type the radicand, and then press Enter: "); + + try + { + var result = Calculator.DoOperation(radicand, operation); + + if (double.IsNaN(result)) + Menu.PrintError("This operation will result in a mathematical error.\n"); + + else Console.WriteLine("Your result: {0:0.##}\n", result); + } + catch (Exception e) + { + Menu.PrintError("Oh no! An exception occurred trying to do the math.\n - Details: " + e.Message); + } + } + + public void PowerOperation(string operation) + { + double baseOperand = Menu.GetOperand("Type the base, and then press Enter: "); + double exponent = Menu.GetOperand("Type the exponent, and then press Enter: "); + + try + { + var result = Calculator.DoOperation(baseOperand, operation, exponent); + + if (double.IsNaN(result)) + Menu.PrintError("This operation will result in a mathematical error.\n"); + + else Console.WriteLine("Your result: {0:0.##}\n", result); + } + catch (Exception e) + { + Menu.PrintError("Oh no! An exception occurred trying to do the math.\n - Details: " + e.Message); + } + } + } +} diff --git a/Calculator.ivangar/Calculator.ivangar/Menu.cs b/Calculator.ivangar/Calculator.ivangar/Menu.cs new file mode 100644 index 00000000..fe9843a1 --- /dev/null +++ b/Calculator.ivangar/Calculator.ivangar/Menu.cs @@ -0,0 +1,67 @@ +namespace Calculator.ivangar +{ + public static class Menu + { + private static readonly Dictionary _operations = new Dictionary() + { + { 'a', "Add"}, + { 's', "Subtract"}, + { 'm', "Multiply"}, + { 'd', "Divide"}, + { 'r', "Square Root"}, + { 'p', "Power"}, + }; + + public static void Intro() + { + Console.WriteLine("Console Calculator in C#\r"); + Console.WriteLine("------------------------\n"); + } + + public static void PrintMenu(bool invalid = false) + { + if (invalid) + Console.WriteLine("\nError: Unrecognized input."); + + Console.WriteLine("\nChoose an operator from the following list:\n"); + PrintMenuOptions(); + } + + public static void PrintMenuOptions() + { + foreach (var (key, op) in _operations) + Console.WriteLine($"\t{key} - {op}"); + + Console.Write("Your option? "); + } + + public static double GetOperand(string message) + { + double cleanNum1; + + Console.Write(message); + string? numInput1 = Console.ReadLine(); + + while (!double.TryParse(numInput1, out cleanNum1)) + { + Console.Write("This is not valid input. Please enter a numeric value: "); + numInput1 = Console.ReadLine(); + } + + return cleanNum1; + } + + public static void PrintError(string message) + { + Console.WriteLine("This operation will result in a mathematical error.\n"); + } + + public static bool ValidateMainOptions(string? option) + { + if (string.IsNullOrEmpty(option) || string.IsNullOrWhiteSpace(option) || option.Length != 1) + return false; + + return _operations.ContainsKey(char.ToLower(option[0])); + } + } +} diff --git a/Calculator.ivangar/Calculator.ivangar/Program.cs b/Calculator.ivangar/Calculator.ivangar/Program.cs index b3351ffa..5f9364cb 100644 --- a/Calculator.ivangar/Calculator.ivangar/Program.cs +++ b/Calculator.ivangar/Calculator.ivangar/Program.cs @@ -1,89 +1,4 @@ -using CalculatorLibrary; -using System.Text.RegularExpressions; +using Calculator.ivangar; -class Program -{ - static void Main(string[] args) - { - bool endApp = false; - // Display title as the C# console calculator app. - Console.WriteLine("Console Calculator in C#\r"); - Console.WriteLine("------------------------\n"); - - var calculator = new Calculator(); - - while (!endApp) - { - // Declare variables and set to empty. - // Use Nullable types (with ?) to match type of System.Console.ReadLine - string? numInput1 = ""; - string? numInput2 = ""; - double result = 0; - - // Ask the user to type the first number. - Console.Write("Type a number, and then press Enter: "); - numInput1 = Console.ReadLine(); - - double cleanNum1 = 0; - while (!double.TryParse(numInput1, out cleanNum1)) - { - Console.Write("This is not valid input. Please enter a numeric value: "); - numInput1 = Console.ReadLine(); - } - - // Ask the user to type the second number. - Console.Write("Type another number, and then press Enter: "); - numInput2 = Console.ReadLine(); - - double cleanNum2 = 0; - while (!double.TryParse(numInput2, out cleanNum2)) - { - Console.Write("This is not valid input. Please enter a numeric value: "); - numInput2 = Console.ReadLine(); - } - - // Ask the user to choose an operator. - Console.WriteLine("Choose an operator from the following list:"); - Console.WriteLine("\ta - Add"); - Console.WriteLine("\ts - Subtract"); - Console.WriteLine("\tm - Multiply"); - Console.WriteLine("\td - Divide"); - Console.Write("Your option? "); - - string? op = Console.ReadLine(); - - // Validate input is not null, and matches the pattern - if (op == null || !Regex.IsMatch(op, "^(a|s|m|d)$")) - { - Console.WriteLine("Error: Unrecognized input."); - } - else - { - try - { - result = calculator.DoOperation(cleanNum1, cleanNum2, 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("Oh no! An exception occurred trying to do the math.\n - Details: " + e.Message); - } - } - Console.WriteLine("------------------------\n"); - - // Wait for the user to respond before closing. - Console.Write("Press 'n' and Enter to close the app, or press any other key and Enter to continue: "); - if (Console.ReadLine() == "n") endApp = true; - - Console.WriteLine("\n"); // Friendly linespacing. - } - - calculator.Finish(); - - return; - } -} \ No newline at end of file +var application = new Application(); +application.Run(); \ No newline at end of file diff --git a/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.cs b/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.cs index dd4d7b41..8613a6b3 100644 --- a/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.cs +++ b/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.cs @@ -1,12 +1,15 @@ -using Newtonsoft.Json; +using CalculatorLibrary.Models; +using Newtonsoft.Json; namespace CalculatorLibrary { - public class Calculator + public class CalculatorEngine { JsonWriter writer; - public Calculator() + private readonly List _operations = new(); + + public CalculatorEngine() { StreamWriter logFile = File.CreateText("calculator.json"); logFile.AutoFlush = true; @@ -17,9 +20,10 @@ public Calculator() writer.WriteStartArray(); } - public double DoOperation(double num1, double num2, string op) + public double DoOperation(double num1, string op, double num2 = 0) { double result = double.NaN; // Default value is "not-a-number" if an operation, such as division, could result in an error. + char operation = default; writer.WriteStartObject(); writer.WritePropertyName("Operand1"); writer.WriteValue(num1); @@ -31,23 +35,47 @@ public double DoOperation(double num1, double num2, string op) switch (op) { case "a": + operation = '+'; result = num1 + num2; - writer.WriteValue('+'); + writer.WriteValue(operation); + AddBasicOperation(num1, num2, operation, result); break; case "s": + operation = '-'; result = num1 - num2; - writer.WriteValue('-'); + writer.WriteValue(operation); + AddBasicOperation(num1, num2, operation, result); break; case "m": + operation = '*'; result = num1 * num2; - writer.WriteValue('*'); + writer.WriteValue(operation); + AddBasicOperation(num1, num2, operation, result); break; case "d": // Ask the user to enter a non-zero divisor. if (num2 != 0) { + operation = '/'; result = num1 / num2; - writer.WriteValue('/'); + writer.WriteValue(operation); + AddBasicOperation(num1, num2, operation, result); + } + break; + case "r": + operation = '√'; + if (TryCalculateSquareRoot(num1, out result)) + { + writer.WriteValue(operation); + AddSquareRootOperation(num1, operation, result); + } + break; + case "p": + operation = '^'; + if (TryCalculateExponent(num1, num2, out result)) + { + writer.WriteValue(operation); + AddPowerOperation(num1, num2, operation, result); } break; // Return text for an incorrect option entry. @@ -67,6 +95,96 @@ public void Finish() writer.WriteEndArray(); writer.WriteEndObject(); writer.Close(); + CountOperations(); + PrintAllOperations(); + } + + public void CountOperations() + { + var countTimes = _operations.Count == 1 ? "time" : "times"; + Console.WriteLine($"The calculator was used {_operations.Count} {countTimes}.\n"); + } + + public void PrintAllOperations() + { + Console.WriteLine("\nLatest Calculations:\n"); + + foreach (var (index, operation) in _operations.Select((o, i) => (i, o))) + { + Console.WriteLine($"{index + 1}. {operation}"); + } + + Console.WriteLine("\n\n"); + } + + public void DeleteOperations() + { + _operations.Clear(); + } + + private void AddBasicOperation(double num1, double num2, char op, double result) + { + _operations.Add(new MathOperation + { + OperandA = num1, + OperandB = num2, + Operation = op, + Result = result + }); + } + + private void AddSquareRootOperation(double radicand, char op, double result) + { + _operations.Add(new SquareRoot + { + Radicand = radicand, + Operation = op, + Result = result + }); + } + + private void AddPowerOperation(double baseNumber, double exponent, char op, double result) + { + _operations.Add(new Exponentiation + { + Base = baseNumber, + Exponent = exponent, + Operation = op, + Result = result + }); + } + + private bool TryCalculateSquareRoot(double radicand, out double result) + { + if (radicand < 0) + { + Console.WriteLine("Cannot compute square root of a negative number."); + result = default; + return false; + } + else + { + result = Math.Round(Math.Sqrt(radicand), 2, MidpointRounding.AwayFromZero); + return true; + } + + } + + private bool TryCalculateExponent(double baseNumber, double exponent, out double result) + { + if (exponent > 10) + { + Console.WriteLine("The exponent is very big, try a smaller number"); + result = default; + return false; + } + + else + { + result = Math.Pow(baseNumber, exponent); + return true; + } + } } } diff --git a/Calculator.ivangar/CalculatorLibrary/Models/Exponentiation.cs b/Calculator.ivangar/CalculatorLibrary/Models/Exponentiation.cs new file mode 100644 index 00000000..b6157117 --- /dev/null +++ b/Calculator.ivangar/CalculatorLibrary/Models/Exponentiation.cs @@ -0,0 +1,13 @@ +namespace CalculatorLibrary.Models +{ + public record Exponentiation : MathOperation + { + public double Base { get; set; } + public double Exponent { get; set; } + + public override string ToString() + { + return $"{Base} ^ {Exponent} = {Result}"; + } + } +} diff --git a/Calculator.ivangar/CalculatorLibrary/Models/MathOperation.cs b/Calculator.ivangar/CalculatorLibrary/Models/MathOperation.cs new file mode 100644 index 00000000..b5ed0e43 --- /dev/null +++ b/Calculator.ivangar/CalculatorLibrary/Models/MathOperation.cs @@ -0,0 +1,11 @@ +namespace CalculatorLibrary.Models +{ + public record MathOperation + { + public double OperandA { get; init; } + public double OperandB { get; init; } + public char Operation { get; init; } + public double Result { get; init; } + public override string ToString() => $"{OperandA} {Operation} {OperandB} = {Result}"; + } +} diff --git a/Calculator.ivangar/CalculatorLibrary/Models/SquareRoot.cs b/Calculator.ivangar/CalculatorLibrary/Models/SquareRoot.cs new file mode 100644 index 00000000..13b455ef --- /dev/null +++ b/Calculator.ivangar/CalculatorLibrary/Models/SquareRoot.cs @@ -0,0 +1,12 @@ +namespace CalculatorLibrary.Models +{ + public record SquareRoot : MathOperation + { + public double Radicand { get; set; } + + public override string ToString() + { + return $"{Operation} {Radicand} = {Result}"; + } + } +} From e26328a61ff41753c02e20acaa4a2a8fe28a6cff Mon Sep 17 00:00:00 2001 From: Ivan Garzon Date: Sat, 19 Sep 2026 18:40:18 -0400 Subject: [PATCH 05/10] Added basic Trigonometry Operations to the calculator. --- .../Calculator.ivangar/Application.cs | 29 +++++++ Calculator.ivangar/Calculator.ivangar/Menu.cs | 1 + .../CalculatorLibrary/CalculatorLibrary.cs | 84 ++++++++++++++++--- .../Enums/TrigonometryFunctions.cs | 9 ++ .../Models/Exponentiation.cs | 6 +- .../CalculatorLibrary/Models/SquareRoot.cs | 5 +- .../Models/TrigonometryOperation.cs | 19 +++++ 7 files changed, 135 insertions(+), 18 deletions(-) create mode 100644 Calculator.ivangar/CalculatorLibrary/Enums/TrigonometryFunctions.cs create mode 100644 Calculator.ivangar/CalculatorLibrary/Models/TrigonometryOperation.cs diff --git a/Calculator.ivangar/Calculator.ivangar/Application.cs b/Calculator.ivangar/Calculator.ivangar/Application.cs index 162923aa..3f921d9b 100644 --- a/Calculator.ivangar/Calculator.ivangar/Application.cs +++ b/Calculator.ivangar/Calculator.ivangar/Application.cs @@ -1,4 +1,5 @@ using CalculatorLibrary; +using CalculatorLibrary.Enums; namespace Calculator.ivangar { @@ -7,6 +8,8 @@ public class Application private bool EndApp = false; private readonly CalculatorEngine Calculator = new(); + private readonly Random _random = new(); + public void Run() { Menu.Intro(); @@ -31,6 +34,9 @@ public void Run() case "p": PowerOperation(op); break; + case "t": + TrigonometryOperation(op); + break; default: BaseMathOperation(op); break; @@ -106,5 +112,28 @@ public void PowerOperation(string operation) Menu.PrintError("Oh no! An exception occurred trying to do the math.\n - Details: " + e.Message); } } + + public void TrigonometryOperation(string operation) + { + double degrees = Menu.GetOperand("Enter an angle in degrees°: "); + var functionValues = Enum.GetValues(); + var randomFunction = _random.Next(functionValues.Length); + var function = functionValues[randomFunction]; + + try + { + // Hard-Coding Sin operation for now, change it to choose randomly from the enum + var result = Calculator.DoTrigonometryOperation(degrees, function, operation); + + if (double.IsNaN(result)) + Menu.PrintError("This operation will result in a mathematical error.\n"); + + else Console.WriteLine("Your result: {0:0.##}\n", result); + } + catch (Exception e) + { + Menu.PrintError("Oh no! An exception occurred trying to do the math.\n - Details: " + e.Message); + } + } } } diff --git a/Calculator.ivangar/Calculator.ivangar/Menu.cs b/Calculator.ivangar/Calculator.ivangar/Menu.cs index fe9843a1..ef6b6864 100644 --- a/Calculator.ivangar/Calculator.ivangar/Menu.cs +++ b/Calculator.ivangar/Calculator.ivangar/Menu.cs @@ -10,6 +10,7 @@ public static class Menu { 'd', "Divide"}, { 'r', "Square Root"}, { 'p', "Power"}, + { 't', "Trigonometry function"}, }; public static void Intro() diff --git a/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.cs b/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.cs index 8613a6b3..cd0d7a0e 100644 --- a/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.cs +++ b/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.cs @@ -1,4 +1,5 @@ -using CalculatorLibrary.Models; +using CalculatorLibrary.Enums; +using CalculatorLibrary.Models; using Newtonsoft.Json; namespace CalculatorLibrary @@ -24,12 +25,7 @@ public double DoOperation(double num1, string op, double num2 = 0) { double result = double.NaN; // Default value is "not-a-number" if an operation, such as division, could result in an error. char operation = default; - writer.WriteStartObject(); - writer.WritePropertyName("Operand1"); - writer.WriteValue(num1); - writer.WritePropertyName("Operand2"); - writer.WriteValue(num2); - writer.WritePropertyName("Operation"); + LogOperationObject(num1, num2); // Use a switch statement to do the math. switch (op) @@ -83,9 +79,25 @@ public double DoOperation(double num1, string op, double num2 = 0) break; } - writer.WritePropertyName("Result"); - writer.WriteValue(result); - writer.WriteEndObject(); + LogResult(result); + return result; + } + + public double DoTrigonometryOperation(double degrees, TrigonometryFunctions function, string op) + { + double result = double.NaN; + char operation = '°'; + + if (TryCalculateTrygonometry(degrees, function, out result)) + { + writer.WriteStartObject(); + writer.WritePropertyName("Operand1"); + writer.WriteValue(degrees); + writer.WritePropertyName("Operation"); + writer.WriteValue(operation); + LogResult(result); + AddTrigOperation(degrees, function, operation, result); + } return result; } @@ -154,6 +166,17 @@ private void AddPowerOperation(double baseNumber, double exponent, char op, doub }); } + private void AddTrigOperation(double degrees, TrigonometryFunctions function, char op, double result) + { + _operations.Add(new TrigonometryOperation + { + Degrees = degrees, + Function = function, + Operation = op, + Result = result + }); + } + private bool TryCalculateSquareRoot(double radicand, out double result) { if (radicand < 0) @@ -184,7 +207,48 @@ private bool TryCalculateExponent(double baseNumber, double exponent, out double result = Math.Pow(baseNumber, exponent); return true; } + } + private bool TryCalculateTrygonometry(double degrees, TrigonometryFunctions function, out double result) + { + if (degrees > 360 || degrees < -360) + { + Console.WriteLine("The degree value is outside of this scope, try a smaller number"); + result = default; + return false; + } + + else + { + var radians = degrees * (Math.PI / 180); + + result = function switch + { + TrigonometryFunctions.Sin => Math.Round(Math.Sin(radians), 4), + TrigonometryFunctions.Cos => Math.Round(Math.Cos(radians), 4), + TrigonometryFunctions.Tan => Math.Round(Math.Tan(radians), 4), + _ => throw new ArgumentOutOfRangeException(nameof(function)) + }; + + return true; + } + } + + private void LogOperationObject(double num1, double num2) + { + writer.WriteStartObject(); + writer.WritePropertyName("Operand1"); + writer.WriteValue(num1); + writer.WritePropertyName("Operand2"); + writer.WriteValue(num2); + writer.WritePropertyName("Operation"); + } + + private void LogResult(double result) + { + writer.WritePropertyName("Result"); + writer.WriteValue(result); + writer.WriteEndObject(); } } } diff --git a/Calculator.ivangar/CalculatorLibrary/Enums/TrigonometryFunctions.cs b/Calculator.ivangar/CalculatorLibrary/Enums/TrigonometryFunctions.cs new file mode 100644 index 00000000..e89be574 --- /dev/null +++ b/Calculator.ivangar/CalculatorLibrary/Enums/TrigonometryFunctions.cs @@ -0,0 +1,9 @@ +namespace CalculatorLibrary.Enums +{ + public enum TrigonometryFunctions + { + Sin, + Cos, + Tan + } +} diff --git a/Calculator.ivangar/CalculatorLibrary/Models/Exponentiation.cs b/Calculator.ivangar/CalculatorLibrary/Models/Exponentiation.cs index b6157117..011900b1 100644 --- a/Calculator.ivangar/CalculatorLibrary/Models/Exponentiation.cs +++ b/Calculator.ivangar/CalculatorLibrary/Models/Exponentiation.cs @@ -5,9 +5,7 @@ public record Exponentiation : MathOperation public double Base { get; set; } public double Exponent { get; set; } - public override string ToString() - { - return $"{Base} ^ {Exponent} = {Result}"; - } + public override string ToString() => $"{Base} ^ {Exponent} = {Result}"; + } } diff --git a/Calculator.ivangar/CalculatorLibrary/Models/SquareRoot.cs b/Calculator.ivangar/CalculatorLibrary/Models/SquareRoot.cs index 13b455ef..d488b18f 100644 --- a/Calculator.ivangar/CalculatorLibrary/Models/SquareRoot.cs +++ b/Calculator.ivangar/CalculatorLibrary/Models/SquareRoot.cs @@ -4,9 +4,6 @@ public record SquareRoot : MathOperation { public double Radicand { get; set; } - public override string ToString() - { - return $"{Operation} {Radicand} = {Result}"; - } + public override string ToString() => $"{Operation} {Radicand} = {Result}"; } } diff --git a/Calculator.ivangar/CalculatorLibrary/Models/TrigonometryOperation.cs b/Calculator.ivangar/CalculatorLibrary/Models/TrigonometryOperation.cs new file mode 100644 index 00000000..52745078 --- /dev/null +++ b/Calculator.ivangar/CalculatorLibrary/Models/TrigonometryOperation.cs @@ -0,0 +1,19 @@ +using CalculatorLibrary.Enums; + +namespace CalculatorLibrary.Models +{ + public record TrigonometryOperation : MathOperation + { + public double Degrees { get; set; } + + // Adding Radians property in case we need to convert later. + public double Radians + { + get { return Degrees * (Math.PI / 180); } + } + + public TrigonometryFunctions Function { get; set; } + + public override string ToString() => $"{Function}({Degrees}{Operation}) = {Result}"; + } +} From ee2a9bd2e907d1f012d4313103059b79119810b5 Mon Sep 17 00:00:00 2001 From: Ivan Garzon Date: Tue, 22 Sep 2026 16:00:11 -0400 Subject: [PATCH 06/10] Added main menu functionality and encapsulated calculations --- .../Calculator.ivangar/Application.cs | 72 +++++++++++++------ .../Enums/MainMenuOptions.cs | 10 +++ Calculator.ivangar/Calculator.ivangar/Menu.cs | 37 ++++++++-- .../CalculatorLibrary/CalculatorLibrary.cs | 15 ++-- 4 files changed, 100 insertions(+), 34 deletions(-) create mode 100644 Calculator.ivangar/Calculator.ivangar/Enums/MainMenuOptions.cs diff --git a/Calculator.ivangar/Calculator.ivangar/Application.cs b/Calculator.ivangar/Calculator.ivangar/Application.cs index 3f921d9b..7e312c6d 100644 --- a/Calculator.ivangar/Calculator.ivangar/Application.cs +++ b/Calculator.ivangar/Calculator.ivangar/Application.cs @@ -1,4 +1,5 @@ -using CalculatorLibrary; +using Calculator.ivangar.Enums; +using CalculatorLibrary; using CalculatorLibrary.Enums; namespace Calculator.ivangar @@ -13,45 +14,73 @@ public class Application public void Run() { Menu.Intro(); + Menu.PrintMenu(); + + string? optionInput = Console.ReadLine(); + MainMenuOptions menuOption; while (!EndApp) { - // Ask the user to choose an operator. - Menu.PrintMenu(); - string? op = Console.ReadLine(); - - while (!Menu.ValidateMainOptions(op)) + while (!Menu.TryGetMenuOption(optionInput, out menuOption)) { Menu.PrintMenu(invalid: true); - op = Console.ReadLine(); + optionInput = Console.ReadLine(); } - switch (op!.ToLower()) + switch (menuOption) { - case "r": - SquareRootOperation(op); + case MainMenuOptions.PerformOperation: + PerformCalculation(); break; - case "p": - PowerOperation(op); + case MainMenuOptions.ViewOperations: + Calculator.PrintAllOperations(); break; - case "t": - TrigonometryOperation(op); + case MainMenuOptions.DeleteOperations: + Calculator.DeleteOperations(); break; - default: - BaseMathOperation(op); + case MainMenuOptions.Exit: + EndApp = true; + Console.WriteLine("\nThank you for using the Calculator."); break; } - Console.WriteLine("------------------------\n"); + if (EndApp) + break; + Menu.PrintMenu(); + optionInput = Console.ReadLine(); + } - Console.Write("Press 'n' and Enter to close the app, or press any other key and Enter to continue: "); - if (Console.ReadLine() == "n") EndApp = true; + Calculator.Finish(); + } - Console.WriteLine("\n"); + public void PerformCalculation() + { + // Ask the user to choose an operator. + Menu.PrintOperations(); + string? op = Console.ReadLine(); + + while (!Menu.ValidateOperationChoice(op)) + { + Menu.PrintOperations(invalid: true); + op = Console.ReadLine(); } - Calculator.Finish(); + switch (op!.ToLower()) + { + case "r": + SquareRootOperation(op); + break; + case "p": + PowerOperation(op); + break; + case "t": + TrigonometryOperation(op); + break; + default: + BaseMathOperation(op); + break; + } } public void BaseMathOperation(string operation) @@ -122,7 +151,6 @@ public void TrigonometryOperation(string operation) try { - // Hard-Coding Sin operation for now, change it to choose randomly from the enum var result = Calculator.DoTrigonometryOperation(degrees, function, operation); if (double.IsNaN(result)) diff --git a/Calculator.ivangar/Calculator.ivangar/Enums/MainMenuOptions.cs b/Calculator.ivangar/Calculator.ivangar/Enums/MainMenuOptions.cs new file mode 100644 index 00000000..4ea27ffd --- /dev/null +++ b/Calculator.ivangar/Calculator.ivangar/Enums/MainMenuOptions.cs @@ -0,0 +1,10 @@ +namespace Calculator.ivangar.Enums +{ + public enum MainMenuOptions + { + PerformOperation = 1, + ViewOperations = 2, + DeleteOperations = 3, + Exit = 4, + } +} diff --git a/Calculator.ivangar/Calculator.ivangar/Menu.cs b/Calculator.ivangar/Calculator.ivangar/Menu.cs index ef6b6864..c4f76f06 100644 --- a/Calculator.ivangar/Calculator.ivangar/Menu.cs +++ b/Calculator.ivangar/Calculator.ivangar/Menu.cs @@ -1,8 +1,10 @@ -namespace Calculator.ivangar +using Calculator.ivangar.Enums; + +namespace Calculator.ivangar { public static class Menu { - private static readonly Dictionary _operations = new Dictionary() + private static readonly Dictionary _operations = new() { { 'a', "Add"}, { 's', "Subtract"}, @@ -22,14 +24,35 @@ public static void Intro() public static void PrintMenu(bool invalid = false) { if (invalid) - Console.WriteLine("\nError: Unrecognized input."); + Console.WriteLine("\nInvalid input."); - Console.WriteLine("\nChoose an operator from the following list:\n"); - PrintMenuOptions(); + Console.WriteLine("\nPlease choose any of the following options (you have to type the number, i.e. 2):\n"); + + foreach (MainMenuOptions option in Enum.GetValues(typeof(MainMenuOptions))) + Console.WriteLine($"\t{(int)option}. {option}"); } - public static void PrintMenuOptions() + public static bool TryGetMenuOption(string? input, out MainMenuOptions menuItem) { + menuItem = default; + + if (!int.TryParse(input, out int optionNumber)) + return false; + + if (!Enum.IsDefined(typeof(MainMenuOptions), optionNumber)) + return false; + + menuItem = (MainMenuOptions)optionNumber; + return true; + } + + public static void PrintOperations(bool invalid = false) + { + if (invalid) + Console.WriteLine("\nError: Unrecognized input."); + + Console.WriteLine("\nChoose an operation from the following list (you have to type the letter, i.e. 'a'):\n"); + foreach (var (key, op) in _operations) Console.WriteLine($"\t{key} - {op}"); @@ -57,7 +80,7 @@ public static void PrintError(string message) Console.WriteLine("This operation will result in a mathematical error.\n"); } - public static bool ValidateMainOptions(string? option) + public static bool ValidateOperationChoice(string? option) { if (string.IsNullOrEmpty(option) || string.IsNullOrWhiteSpace(option) || option.Length != 1) return false; diff --git a/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.cs b/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.cs index cd0d7a0e..0d123105 100644 --- a/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.cs +++ b/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.cs @@ -119,18 +119,23 @@ public void CountOperations() public void PrintAllOperations() { - Console.WriteLine("\nLatest Calculations:\n"); - - foreach (var (index, operation) in _operations.Select((o, i) => (i, o))) + if (_operations.Count != 0) { - Console.WriteLine($"{index + 1}. {operation}"); + Console.WriteLine("\nLatest calculations:\n"); + + foreach (var (index, operation) in _operations.Select((o, i) => (i, o))) + { + Console.WriteLine($"{index + 1}. {operation}"); + } } - Console.WriteLine("\n\n"); + else + Console.WriteLine("\nThere are no calculations to display:\n"); } public void DeleteOperations() { + Console.WriteLine("\nDeleting all current operations:\n"); _operations.Clear(); } From 4f3394ca2be51ef69b80adc56a3b1aa111e637ab Mon Sep 17 00:00:00 2001 From: Ivan Garzon Date: Wed, 23 Sep 2026 17:17:16 -0400 Subject: [PATCH 07/10] Replaced Newtonsoft JsonTextWriter with Utf8JsonWriter. --- .../Calculator.ivangar/Application.cs | 8 -- .../CalculatorLibrary/CalculatorLibrary.cs | 130 +++++++++++------- .../CalculatorLibrary.csproj | 4 - .../Models/Exponentiation.cs | 2 +- .../CalculatorLibrary/Models/MathOperation.cs | 2 +- .../CalculatorLibrary/Models/SquareRoot.cs | 2 +- .../Models/TrigonometryOperation.cs | 2 +- 7 files changed, 85 insertions(+), 65 deletions(-) diff --git a/Calculator.ivangar/Calculator.ivangar/Application.cs b/Calculator.ivangar/Calculator.ivangar/Application.cs index 7e312c6d..7c6b9fef 100644 --- a/Calculator.ivangar/Calculator.ivangar/Application.cs +++ b/Calculator.ivangar/Calculator.ivangar/Application.cs @@ -94,8 +94,6 @@ public void BaseMathOperation(string operation) if (double.IsNaN(result)) Menu.PrintError("This operation will result in a mathematical error.\n"); - - else Console.WriteLine("Your result: {0:0.##}\n", result); } catch (Exception e) { @@ -113,8 +111,6 @@ public void SquareRootOperation(string operation) if (double.IsNaN(result)) Menu.PrintError("This operation will result in a mathematical error.\n"); - - else Console.WriteLine("Your result: {0:0.##}\n", result); } catch (Exception e) { @@ -133,8 +129,6 @@ public void PowerOperation(string operation) if (double.IsNaN(result)) Menu.PrintError("This operation will result in a mathematical error.\n"); - - else Console.WriteLine("Your result: {0:0.##}\n", result); } catch (Exception e) { @@ -155,8 +149,6 @@ public void TrigonometryOperation(string operation) if (double.IsNaN(result)) Menu.PrintError("This operation will result in a mathematical error.\n"); - - else Console.WriteLine("Your result: {0:0.##}\n", result); } catch (Exception e) { diff --git a/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.cs b/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.cs index 0d123105..f36afdb7 100644 --- a/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.cs +++ b/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.cs @@ -1,24 +1,32 @@ using CalculatorLibrary.Enums; using CalculatorLibrary.Models; -using Newtonsoft.Json; +using System.Text.Encodings.Web; +using System.Text.Json; namespace CalculatorLibrary { public class CalculatorEngine { - JsonWriter writer; + private readonly Utf8JsonWriter _writer; private readonly List _operations = new(); + private int _operationCount = 0; + public CalculatorEngine() { - StreamWriter logFile = File.CreateText("calculator.json"); - logFile.AutoFlush = true; - writer = new JsonTextWriter(logFile); - writer.Formatting = Formatting.Indented; - writer.WriteStartObject(); - writer.WritePropertyName("Operations"); - writer.WriteStartArray(); + var stream = new FileStream("calculator.json", FileMode.Create, FileAccess.Write, FileShare.None); + var options = new JsonWriterOptions + { + Indented = true, + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + }; + + _writer = new Utf8JsonWriter(stream, options); + + _writer.WriteStartObject(); + _writer.WritePropertyName("Operations"); + _writer.WriteStartArray(); } public double DoOperation(double num1, string op, double num2 = 0) @@ -33,52 +41,51 @@ public double DoOperation(double num1, string op, double num2 = 0) case "a": operation = '+'; result = num1 + num2; - writer.WriteValue(operation); + _writer.WriteStringValue(operation.ToString()); AddBasicOperation(num1, num2, operation, result); break; case "s": operation = '-'; result = num1 - num2; - writer.WriteValue(operation); + _writer.WriteStringValue(operation.ToString()); AddBasicOperation(num1, num2, operation, result); break; case "m": operation = '*'; result = num1 * num2; - writer.WriteValue(operation); + _writer.WriteStringValue(operation.ToString()); AddBasicOperation(num1, num2, operation, result); break; case "d": - // Ask the user to enter a non-zero divisor. - if (num2 != 0) + operation = '/'; + _writer.WriteStringValue(operation.ToString()); + if (TryDivide(num1, num2, out result)) { - operation = '/'; - result = num1 / num2; - writer.WriteValue(operation); AddBasicOperation(num1, num2, operation, result); } break; case "r": operation = '√'; + _writer.WriteStringValue(operation.ToString()); if (TryCalculateSquareRoot(num1, out result)) { - writer.WriteValue(operation); AddSquareRootOperation(num1, operation, result); } break; case "p": operation = '^'; + _writer.WriteStringValue(operation.ToString()); if (TryCalculateExponent(num1, num2, out result)) { - writer.WriteValue(operation); AddPowerOperation(num1, num2, operation, result); } break; - // Return text for an incorrect option entry. default: + Console.WriteLine("This operation does not exist"); break; } + _operationCount++; LogResult(result); return result; } @@ -90,12 +97,11 @@ public double DoTrigonometryOperation(double degrees, TrigonometryFunctions func if (TryCalculateTrygonometry(degrees, function, out result)) { - writer.WriteStartObject(); - writer.WritePropertyName("Operand1"); - writer.WriteValue(degrees); - writer.WritePropertyName("Operation"); - writer.WriteValue(operation); + _writer.WriteStartObject(); + _writer.WriteNumber("Operand1", degrees); + _writer.WriteString("Operation", operation.ToString()); LogResult(result); + AddTrigOperation(degrees, function, operation, result); } @@ -104,24 +110,26 @@ public double DoTrigonometryOperation(double degrees, TrigonometryFunctions func public void Finish() { - writer.WriteEndArray(); - writer.WriteEndObject(); - writer.Close(); - CountOperations(); + _writer.WriteEndArray(); + _writer.WriteEndObject(); + _writer.Dispose(); + PrintAllOperations(); } public void CountOperations() { - var countTimes = _operations.Count == 1 ? "time" : "times"; - Console.WriteLine($"The calculator was used {_operations.Count} {countTimes}.\n"); + var countTimes = _operationCount == 1 ? "time" : "times"; + Console.WriteLine($"\nThe calculator was used {_operations.Count} {countTimes}.\n"); } public void PrintAllOperations() { + CountOperations(); + if (_operations.Count != 0) { - Console.WriteLine("\nLatest calculations:\n"); + Console.WriteLine("Latest calculations:\n"); foreach (var (index, operation) in _operations.Select((o, i) => (i, o))) { @@ -141,45 +149,72 @@ public void DeleteOperations() private void AddBasicOperation(double num1, double num2, char op, double result) { - _operations.Add(new MathOperation + var operation = new MathOperation { OperandA = num1, OperandB = num2, Operation = op, Result = result - }); + }; + + _operations.Add(operation); + Console.WriteLine($"Operation: {operation}\n"); } private void AddSquareRootOperation(double radicand, char op, double result) { - _operations.Add(new SquareRoot + var operation = new SquareRoot { Radicand = radicand, Operation = op, Result = result - }); + }; + + _operations.Add(operation); + Console.WriteLine($"Operation: {operation}\n"); } private void AddPowerOperation(double baseNumber, double exponent, char op, double result) { - _operations.Add(new Exponentiation + var operation = new Exponentiation { Base = baseNumber, Exponent = exponent, Operation = op, Result = result - }); + }; + + _operations.Add(operation); + Console.WriteLine($"Operation: {operation}\n"); } private void AddTrigOperation(double degrees, TrigonometryFunctions function, char op, double result) { - _operations.Add(new TrigonometryOperation + var operation = new TrigonometryOperation { Degrees = degrees, Function = function, Operation = op, Result = result - }); + }; + + _operations.Add(operation); + Console.WriteLine($"Operation: {operation}\n"); + } + + private bool TryDivide(double num1, double num2, out double result) + { + if (num2 == 0) + { + Console.WriteLine("Cannot divide by zero."); + result = default; + return false; + } + else + { + result = num1 / num2; + return true; + } } private bool TryCalculateSquareRoot(double radicand, out double result) @@ -241,19 +276,16 @@ private bool TryCalculateTrygonometry(double degrees, TrigonometryFunctions func private void LogOperationObject(double num1, double num2) { - writer.WriteStartObject(); - writer.WritePropertyName("Operand1"); - writer.WriteValue(num1); - writer.WritePropertyName("Operand2"); - writer.WriteValue(num2); - writer.WritePropertyName("Operation"); + _writer.WriteStartObject(); + _writer.WriteNumber("Operand1", num1); + _writer.WriteNumber("Operand2", num2); + _writer.WritePropertyName("Operation"); } private void LogResult(double result) { - writer.WritePropertyName("Result"); - writer.WriteValue(result); - writer.WriteEndObject(); + _writer.WriteNumber("Result", Math.Round(result, 2, MidpointRounding.AwayFromZero)); + _writer.WriteEndObject(); } } } diff --git a/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.csproj b/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.csproj index 22badd14..b7601447 100644 --- a/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.csproj +++ b/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.csproj @@ -6,8 +6,4 @@ enable - - - - diff --git a/Calculator.ivangar/CalculatorLibrary/Models/Exponentiation.cs b/Calculator.ivangar/CalculatorLibrary/Models/Exponentiation.cs index 011900b1..feee8336 100644 --- a/Calculator.ivangar/CalculatorLibrary/Models/Exponentiation.cs +++ b/Calculator.ivangar/CalculatorLibrary/Models/Exponentiation.cs @@ -5,7 +5,7 @@ public record Exponentiation : MathOperation public double Base { get; set; } public double Exponent { get; set; } - public override string ToString() => $"{Base} ^ {Exponent} = {Result}"; + public override string ToString() => $"{Base} ^ {Exponent} = {Result:0.##}"; } } diff --git a/Calculator.ivangar/CalculatorLibrary/Models/MathOperation.cs b/Calculator.ivangar/CalculatorLibrary/Models/MathOperation.cs index b5ed0e43..d98e07dd 100644 --- a/Calculator.ivangar/CalculatorLibrary/Models/MathOperation.cs +++ b/Calculator.ivangar/CalculatorLibrary/Models/MathOperation.cs @@ -6,6 +6,6 @@ public record MathOperation public double OperandB { get; init; } public char Operation { get; init; } public double Result { get; init; } - public override string ToString() => $"{OperandA} {Operation} {OperandB} = {Result}"; + public override string ToString() => $"{OperandA} {Operation} {OperandB} = {Result:0.##}"; } } diff --git a/Calculator.ivangar/CalculatorLibrary/Models/SquareRoot.cs b/Calculator.ivangar/CalculatorLibrary/Models/SquareRoot.cs index d488b18f..f711b6e2 100644 --- a/Calculator.ivangar/CalculatorLibrary/Models/SquareRoot.cs +++ b/Calculator.ivangar/CalculatorLibrary/Models/SquareRoot.cs @@ -4,6 +4,6 @@ public record SquareRoot : MathOperation { public double Radicand { get; set; } - public override string ToString() => $"{Operation} {Radicand} = {Result}"; + public override string ToString() => $"{Operation} {Radicand} = {Result:0.##}"; } } diff --git a/Calculator.ivangar/CalculatorLibrary/Models/TrigonometryOperation.cs b/Calculator.ivangar/CalculatorLibrary/Models/TrigonometryOperation.cs index 52745078..516a9086 100644 --- a/Calculator.ivangar/CalculatorLibrary/Models/TrigonometryOperation.cs +++ b/Calculator.ivangar/CalculatorLibrary/Models/TrigonometryOperation.cs @@ -14,6 +14,6 @@ public double Radians public TrigonometryFunctions Function { get; set; } - public override string ToString() => $"{Function}({Degrees}{Operation}) = {Result}"; + public override string ToString() => $"{Function}({Degrees}{Operation}) = {Result:0.##}"; } } From d411630e7b8ac09337cc757169a32477b4d392bf Mon Sep 17 00:00:00 2001 From: Ivan Garzon Date: Fri, 25 Sep 2026 13:12:11 -0400 Subject: [PATCH 08/10] Added CalculatorLogWriter class to extract logging functionality --- .../CalculatorLibrary/CalculatorLibrary.cs | 72 ++++------ .../Logging/CalculatorLogWriter.cs | 127 ++++++++++++++++++ 2 files changed, 150 insertions(+), 49 deletions(-) create mode 100644 Calculator.ivangar/CalculatorLibrary/Logging/CalculatorLogWriter.cs diff --git a/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.cs b/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.cs index f36afdb7..11e32e1f 100644 --- a/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.cs +++ b/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.cs @@ -1,39 +1,25 @@ using CalculatorLibrary.Enums; +using CalculatorLibrary.Logging; using CalculatorLibrary.Models; -using System.Text.Encodings.Web; -using System.Text.Json; namespace CalculatorLibrary { public class CalculatorEngine { - private readonly Utf8JsonWriter _writer; - + private readonly CalculatorLogWriter _log; private readonly List _operations = new(); - private int _operationCount = 0; + private bool SuccessfullOperation = true; public CalculatorEngine() { - var stream = new FileStream("calculator.json", FileMode.Create, FileAccess.Write, FileShare.None); - var options = new JsonWriterOptions - { - Indented = true, - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping - }; - - _writer = new Utf8JsonWriter(stream, options); - - _writer.WriteStartObject(); - _writer.WritePropertyName("Operations"); - _writer.WriteStartArray(); + _log = new CalculatorLogWriter(); } public double DoOperation(double num1, string op, double num2 = 0) { double result = double.NaN; // Default value is "not-a-number" if an operation, such as division, could result in an error. char operation = default; - LogOperationObject(num1, num2); // Use a switch statement to do the math. switch (op) @@ -41,52 +27,60 @@ public double DoOperation(double num1, string op, double num2 = 0) case "a": operation = '+'; result = num1 + num2; - _writer.WriteStringValue(operation.ToString()); AddBasicOperation(num1, num2, operation, result); break; case "s": operation = '-'; result = num1 - num2; - _writer.WriteStringValue(operation.ToString()); AddBasicOperation(num1, num2, operation, result); break; case "m": operation = '*'; result = num1 * num2; - _writer.WriteStringValue(operation.ToString()); AddBasicOperation(num1, num2, operation, result); break; case "d": operation = '/'; - _writer.WriteStringValue(operation.ToString()); if (TryDivide(num1, num2, out result)) { AddBasicOperation(num1, num2, operation, result); } + else + SuccessfullOperation = false; break; case "r": operation = '√'; - _writer.WriteStringValue(operation.ToString()); if (TryCalculateSquareRoot(num1, out result)) { AddSquareRootOperation(num1, operation, result); } + else + SuccessfullOperation = false; break; case "p": operation = '^'; - _writer.WriteStringValue(operation.ToString()); if (TryCalculateExponent(num1, num2, out result)) { AddPowerOperation(num1, num2, operation, result); } + else + SuccessfullOperation = false; break; default: Console.WriteLine("This operation does not exist"); + SuccessfullOperation = false; break; } - _operationCount++; - LogResult(result); + if (SuccessfullOperation) + { + _operationCount++; + if (operation == '√') + _log.WriteOperation(num1, operation, result); + else + _log.WriteOperation(num1, num2, operation, result); + } + return result; } @@ -97,11 +91,7 @@ public double DoTrigonometryOperation(double degrees, TrigonometryFunctions func if (TryCalculateTrygonometry(degrees, function, out result)) { - _writer.WriteStartObject(); - _writer.WriteNumber("Operand1", degrees); - _writer.WriteString("Operation", operation.ToString()); - LogResult(result); - + _log.WriteOperation(degrees, operation, result); AddTrigOperation(degrees, function, operation, result); } @@ -110,10 +100,7 @@ public double DoTrigonometryOperation(double degrees, TrigonometryFunctions func public void Finish() { - _writer.WriteEndArray(); - _writer.WriteEndObject(); - _writer.Dispose(); - + _log.Dispose(); PrintAllOperations(); } @@ -145,6 +132,7 @@ public void DeleteOperations() { Console.WriteLine("\nDeleting all current operations:\n"); _operations.Clear(); + _log.DeleteOperations(); } private void AddBasicOperation(double num1, double num2, char op, double result) @@ -273,19 +261,5 @@ private bool TryCalculateTrygonometry(double degrees, TrigonometryFunctions func return true; } } - - private void LogOperationObject(double num1, double num2) - { - _writer.WriteStartObject(); - _writer.WriteNumber("Operand1", num1); - _writer.WriteNumber("Operand2", num2); - _writer.WritePropertyName("Operation"); - } - - private void LogResult(double result) - { - _writer.WriteNumber("Result", Math.Round(result, 2, MidpointRounding.AwayFromZero)); - _writer.WriteEndObject(); - } } } diff --git a/Calculator.ivangar/CalculatorLibrary/Logging/CalculatorLogWriter.cs b/Calculator.ivangar/CalculatorLibrary/Logging/CalculatorLogWriter.cs new file mode 100644 index 00000000..a6a77443 --- /dev/null +++ b/Calculator.ivangar/CalculatorLibrary/Logging/CalculatorLogWriter.cs @@ -0,0 +1,127 @@ +using System.Text.Encodings.Web; +using System.Text.Json; + +namespace CalculatorLibrary.Logging +{ + public class CalculatorLogWriter : IDisposable + { + private Utf8JsonWriter _writer; + private FileStream _stream; + private readonly string _filePath; + + public CalculatorLogWriter(string filePath = "calculator.json") + { + _filePath = filePath; + InitializeWriter(); + } + + public void WriteOperation(double operand1, double operand2, char symbol, double result) + { + _writer.WriteStartObject(); + _writer.WriteNumber("Operand1", operand1); + _writer.WriteNumber("Operand2", operand2); + _writer.WriteString("Operation", symbol.ToString()); + WriteResult(result); + } + + public void WriteOperation(double operand1, char symbol, double result) + { + _writer.WriteStartObject(); + _writer.WriteNumber("Operand1", operand1); + _writer.WriteString("Operation", symbol.ToString()); + WriteResult(result); + } + + public void WriteOperationSymbol(char symbol) + { + _writer.WriteStringValue(symbol.ToString()); + } + + public void WriteResult(double result) + { + _writer.WriteNumber("Result", result); + _writer.WriteEndObject(); + } + + public void DeleteOperations() + { + // Close writer AND stream + Dispose(); + _stream.Dispose(); + + // Read existing JSON to check if operations exist + string json = File.ReadAllText(_filePath); + + using var doc = JsonDocument.Parse(json); + var root = doc.RootElement; + + if (!root.TryGetProperty("Operations", out var ops) || ops.GetArrayLength() == 0) + { + Console.WriteLine("No operations to delete."); + InitializeWriter(); // reopen writer so logging continues + return; + } + + Console.WriteLine("Deleting all operations from log file."); + + EmptyOperations(); + InitializeWriter(); + } + + public void Finish() + { + _writer.WriteEndArray(); + _writer.WriteEndObject(); + } + + public void Dispose() + { + Finish(); + _writer.Dispose(); + } + + // Rewrite file with empty Operations array + private void EmptyOperations() + { + using var stream = new FileStream(_filePath, FileMode.Create, FileAccess.Write, FileShare.None); + var options = new JsonWriterOptions + { + Indented = true, + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + }; + + using var newWriter = new Utf8JsonWriter(stream, options); + + newWriter.WriteStartObject(); + newWriter.WritePropertyName("Operations"); + newWriter.WriteStartArray(); + newWriter.WriteEndArray(); + newWriter.WriteEndObject(); + + newWriter.Flush(); + + Dispose(); + + InitializeWriter(); + } + + // Initialize writer for logging + private void InitializeWriter() + { + _stream = new FileStream(_filePath, FileMode.Create, FileAccess.Write, FileShare.None); + + var options = new JsonWriterOptions + { + Indented = true, + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + }; + + _writer = new Utf8JsonWriter(_stream, options); + + // Move writer to the end of the Operations array + _writer.WriteStartObject(); + _writer.WritePropertyName("Operations"); + _writer.WriteStartArray(); + } + } +} From a3004ec46c75d926126b893e3eafa08ea5ae4838 Mon Sep 17 00:00:00 2001 From: Ivan Garzon Date: Mon, 28 Sep 2026 10:01:30 -0400 Subject: [PATCH 09/10] Fixed bug related to multiple FileStreams opened and active when calling Dispose --- .../CalculatorLibrary/CalculatorLibrary.cs | 5 ++- .../Logging/CalculatorLogWriter.cs | 35 ++++++++++--------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.cs b/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.cs index 11e32e1f..72443c06 100644 --- a/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.cs +++ b/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.cs @@ -18,10 +18,9 @@ public CalculatorEngine() public double DoOperation(double num1, string op, double num2 = 0) { - double result = double.NaN; // Default value is "not-a-number" if an operation, such as division, could result in an error. + double result = double.NaN; char operation = default; - // Use a switch statement to do the math. switch (op) { case "a": @@ -91,7 +90,7 @@ public double DoTrigonometryOperation(double degrees, TrigonometryFunctions func if (TryCalculateTrygonometry(degrees, function, out result)) { - _log.WriteOperation(degrees, operation, result); + _log.WriteTrigOperation(degrees, operation, function, result); AddTrigOperation(degrees, function, operation, result); } diff --git a/Calculator.ivangar/CalculatorLibrary/Logging/CalculatorLogWriter.cs b/Calculator.ivangar/CalculatorLibrary/Logging/CalculatorLogWriter.cs index a6a77443..ff618bbd 100644 --- a/Calculator.ivangar/CalculatorLibrary/Logging/CalculatorLogWriter.cs +++ b/Calculator.ivangar/CalculatorLibrary/Logging/CalculatorLogWriter.cs @@ -1,4 +1,5 @@ -using System.Text.Encodings.Web; +using CalculatorLibrary.Enums; +using System.Text.Encodings.Web; using System.Text.Json; namespace CalculatorLibrary.Logging @@ -32,9 +33,12 @@ public void WriteOperation(double operand1, char symbol, double result) WriteResult(result); } - public void WriteOperationSymbol(char symbol) + public void WriteTrigOperation(double operand1, char symbol, TrigonometryFunctions function, double result) { - _writer.WriteStringValue(symbol.ToString()); + _writer.WriteStartObject(); + _writer.WriteNumber("Operand1", operand1); + _writer.WriteString("Operation", $"{function}{symbol}"); + WriteResult(result); } public void WriteResult(double result) @@ -49,7 +53,6 @@ public void DeleteOperations() Dispose(); _stream.Dispose(); - // Read existing JSON to check if operations exist string json = File.ReadAllText(_filePath); using var doc = JsonDocument.Parse(json); @@ -58,14 +61,13 @@ public void DeleteOperations() if (!root.TryGetProperty("Operations", out var ops) || ops.GetArrayLength() == 0) { Console.WriteLine("No operations to delete."); - InitializeWriter(); // reopen writer so logging continues + InitializeWriter(); return; } Console.WriteLine("Deleting all operations from log file."); EmptyOperations(); - InitializeWriter(); } public void Finish() @@ -83,24 +85,24 @@ public void Dispose() // Rewrite file with empty Operations array private void EmptyOperations() { - using var stream = new FileStream(_filePath, FileMode.Create, FileAccess.Write, FileShare.None); var options = new JsonWriterOptions { Indented = true, Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping }; - using var newWriter = new Utf8JsonWriter(stream, options); - - newWriter.WriteStartObject(); - newWriter.WritePropertyName("Operations"); - newWriter.WriteStartArray(); - newWriter.WriteEndArray(); - newWriter.WriteEndObject(); + using (var stream = new FileStream(_filePath, FileMode.Create, FileAccess.Write, FileShare.None)) + { + using var newWriter = new Utf8JsonWriter(stream, options); - newWriter.Flush(); + newWriter.WriteStartObject(); + newWriter.WritePropertyName("Operations"); + newWriter.WriteStartArray(); + newWriter.WriteEndArray(); + newWriter.WriteEndObject(); - Dispose(); + newWriter.Flush(); + } InitializeWriter(); } @@ -118,7 +120,6 @@ private void InitializeWriter() _writer = new Utf8JsonWriter(_stream, options); - // Move writer to the end of the Operations array _writer.WriteStartObject(); _writer.WritePropertyName("Operations"); _writer.WriteStartArray(); From d44747a490de02e7b1d607d0463adbc10d5f3d21 Mon Sep 17 00:00:00 2001 From: Ivan Garzon Date: Mon, 28 Sep 2026 11:23:08 -0400 Subject: [PATCH 10/10] Extracting Calculator Library operations into small utility classes. --- .../Calculator.ivangar/Application.cs | 16 +- Calculator.ivangar/Calculator.ivangar/Menu.cs | 5 - .../CalculatorLibrary/CalculatorLibrary.cs | 199 +++--------------- .../CalculatorLibrary/CalculatorMath.cs | 67 ++++++ .../CalculatorLibrary/OperationFactory.cs | 20 ++ .../CalculatorLibrary/OperationRepository.cs | 39 ++++ 6 files changed, 163 insertions(+), 183 deletions(-) create mode 100644 Calculator.ivangar/CalculatorLibrary/CalculatorMath.cs create mode 100644 Calculator.ivangar/CalculatorLibrary/OperationFactory.cs create mode 100644 Calculator.ivangar/CalculatorLibrary/OperationRepository.cs diff --git a/Calculator.ivangar/Calculator.ivangar/Application.cs b/Calculator.ivangar/Calculator.ivangar/Application.cs index 7c6b9fef..5a497bc3 100644 --- a/Calculator.ivangar/Calculator.ivangar/Application.cs +++ b/Calculator.ivangar/Calculator.ivangar/Application.cs @@ -93,11 +93,11 @@ public void BaseMathOperation(string operation) var result = Calculator.DoOperation(operand1, operation, operand2); if (double.IsNaN(result)) - Menu.PrintError("This operation will result in a mathematical error.\n"); + Console.WriteLine("This operation will result in a mathematical error.\n"); } catch (Exception e) { - Menu.PrintError("Oh no! An exception occurred trying to do the math.\n - Details: " + e.Message); + Console.WriteLine("Oh no! An exception occurred trying to do the math.\n - Details: " + e.Message); } } @@ -110,11 +110,11 @@ public void SquareRootOperation(string operation) var result = Calculator.DoOperation(radicand, operation); if (double.IsNaN(result)) - Menu.PrintError("This operation will result in a mathematical error.\n"); + Console.WriteLine("This operation will result in a mathematical error.\n"); } catch (Exception e) { - Menu.PrintError("Oh no! An exception occurred trying to do the math.\n - Details: " + e.Message); + Console.WriteLine("Oh no! An exception occurred trying to do the math.\n - Details: " + e.Message); } } @@ -128,11 +128,11 @@ public void PowerOperation(string operation) var result = Calculator.DoOperation(baseOperand, operation, exponent); if (double.IsNaN(result)) - Menu.PrintError("This operation will result in a mathematical error.\n"); + Console.WriteLine("This operation will result in a mathematical error.\n"); } catch (Exception e) { - Menu.PrintError("Oh no! An exception occurred trying to do the math.\n - Details: " + e.Message); + Console.WriteLine("Oh no! An exception occurred trying to do the math.\n - Details: " + e.Message); } } @@ -148,11 +148,11 @@ public void TrigonometryOperation(string operation) var result = Calculator.DoTrigonometryOperation(degrees, function, operation); if (double.IsNaN(result)) - Menu.PrintError("This operation will result in a mathematical error.\n"); + Console.WriteLine("This operation will result in a mathematical error.\n"); } catch (Exception e) { - Menu.PrintError("Oh no! An exception occurred trying to do the math.\n - Details: " + e.Message); + Console.WriteLine("Oh no! An exception occurred trying to do the math.\n - Details: " + e.Message); } } } diff --git a/Calculator.ivangar/Calculator.ivangar/Menu.cs b/Calculator.ivangar/Calculator.ivangar/Menu.cs index c4f76f06..1c44e2d6 100644 --- a/Calculator.ivangar/Calculator.ivangar/Menu.cs +++ b/Calculator.ivangar/Calculator.ivangar/Menu.cs @@ -75,11 +75,6 @@ public static double GetOperand(string message) return cleanNum1; } - public static void PrintError(string message) - { - Console.WriteLine("This operation will result in a mathematical error.\n"); - } - public static bool ValidateOperationChoice(string? option) { if (string.IsNullOrEmpty(option) || string.IsNullOrWhiteSpace(option) || option.Length != 1) diff --git a/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.cs b/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.cs index 72443c06..990b9693 100644 --- a/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.cs +++ b/Calculator.ivangar/CalculatorLibrary/CalculatorLibrary.cs @@ -1,79 +1,83 @@ using CalculatorLibrary.Enums; using CalculatorLibrary.Logging; -using CalculatorLibrary.Models; namespace CalculatorLibrary { public class CalculatorEngine { private readonly CalculatorLogWriter _log; - private readonly List _operations = new(); - private int _operationCount = 0; - private bool SuccessfullOperation = true; + private readonly OperationRepository _operationRepository; public CalculatorEngine() { _log = new CalculatorLogWriter(); + _operationRepository = new OperationRepository(); } public double DoOperation(double num1, string op, double num2 = 0) { double result = double.NaN; char operation = default; + bool successfullOperation = true; switch (op) { case "a": operation = '+'; result = num1 + num2; - AddBasicOperation(num1, num2, operation, result); + var sum = OperationFactory.CreateBasic(num1, num2, operation, result); + _operationRepository.Add(sum); break; case "s": operation = '-'; result = num1 - num2; - AddBasicOperation(num1, num2, operation, result); + var subtraction = OperationFactory.CreateBasic(num1, num2, operation, result); + _operationRepository.Add(subtraction); break; case "m": operation = '*'; result = num1 * num2; - AddBasicOperation(num1, num2, operation, result); + var multiplication = OperationFactory.CreateBasic(num1, num2, operation, result); + _operationRepository.Add(multiplication); break; case "d": operation = '/'; - if (TryDivide(num1, num2, out result)) + if (CalculatorMath.TryDivide(num1, num2, out result)) { - AddBasicOperation(num1, num2, operation, result); + var division = OperationFactory.CreateBasic(num1, num2, operation, result); + _operationRepository.Add(division); } else - SuccessfullOperation = false; + successfullOperation = false; break; case "r": operation = '√'; - if (TryCalculateSquareRoot(num1, out result)) + if (CalculatorMath.TryCalculateSquareRoot(num1, out result)) { - AddSquareRootOperation(num1, operation, result); + var squareRoot = OperationFactory.CreateSquareRoot(num1, operation, result); + _operationRepository.Add(squareRoot); } else - SuccessfullOperation = false; + successfullOperation = false; break; case "p": operation = '^'; - if (TryCalculateExponent(num1, num2, out result)) + if (CalculatorMath.TryCalculateExponent(num1, num2, out result)) { - AddPowerOperation(num1, num2, operation, result); + var power = OperationFactory.CreateExponentiation(num1, num2, operation, result); + _operationRepository.Add(power); } else - SuccessfullOperation = false; + successfullOperation = false; break; default: Console.WriteLine("This operation does not exist"); - SuccessfullOperation = false; + successfullOperation = false; break; } - if (SuccessfullOperation) + if (successfullOperation) { - _operationCount++; if (operation == '√') _log.WriteOperation(num1, operation, result); else @@ -88,10 +92,11 @@ public double DoTrigonometryOperation(double degrees, TrigonometryFunctions func double result = double.NaN; char operation = '°'; - if (TryCalculateTrygonometry(degrees, function, out result)) + if (CalculatorMath.TryCalculateTrigonometry(degrees, function, out result)) { _log.WriteTrigOperation(degrees, operation, function, result); - AddTrigOperation(degrees, function, operation, result); + var trigOperation = OperationFactory.CreateTrigonometry(degrees, function, operation, result); + _operationRepository.Add(trigOperation); } return result; @@ -100,165 +105,19 @@ public double DoTrigonometryOperation(double degrees, TrigonometryFunctions func public void Finish() { _log.Dispose(); - PrintAllOperations(); - } - - public void CountOperations() - { - var countTimes = _operationCount == 1 ? "time" : "times"; - Console.WriteLine($"\nThe calculator was used {_operations.Count} {countTimes}.\n"); + _operationRepository.PrintAll(); } public void PrintAllOperations() { - CountOperations(); - - if (_operations.Count != 0) - { - Console.WriteLine("Latest calculations:\n"); - - foreach (var (index, operation) in _operations.Select((o, i) => (i, o))) - { - Console.WriteLine($"{index + 1}. {operation}"); - } - } - - else - Console.WriteLine("\nThere are no calculations to display:\n"); + _operationRepository.PrintAll(); } public void DeleteOperations() { Console.WriteLine("\nDeleting all current operations:\n"); - _operations.Clear(); + _operationRepository.Clear(); _log.DeleteOperations(); } - - private void AddBasicOperation(double num1, double num2, char op, double result) - { - var operation = new MathOperation - { - OperandA = num1, - OperandB = num2, - Operation = op, - Result = result - }; - - _operations.Add(operation); - Console.WriteLine($"Operation: {operation}\n"); - } - - private void AddSquareRootOperation(double radicand, char op, double result) - { - var operation = new SquareRoot - { - Radicand = radicand, - Operation = op, - Result = result - }; - - _operations.Add(operation); - Console.WriteLine($"Operation: {operation}\n"); - } - - private void AddPowerOperation(double baseNumber, double exponent, char op, double result) - { - var operation = new Exponentiation - { - Base = baseNumber, - Exponent = exponent, - Operation = op, - Result = result - }; - - _operations.Add(operation); - Console.WriteLine($"Operation: {operation}\n"); - } - - private void AddTrigOperation(double degrees, TrigonometryFunctions function, char op, double result) - { - var operation = new TrigonometryOperation - { - Degrees = degrees, - Function = function, - Operation = op, - Result = result - }; - - _operations.Add(operation); - Console.WriteLine($"Operation: {operation}\n"); - } - - private bool TryDivide(double num1, double num2, out double result) - { - if (num2 == 0) - { - Console.WriteLine("Cannot divide by zero."); - result = default; - return false; - } - else - { - result = num1 / num2; - return true; - } - } - - private bool TryCalculateSquareRoot(double radicand, out double result) - { - if (radicand < 0) - { - Console.WriteLine("Cannot compute square root of a negative number."); - result = default; - return false; - } - else - { - result = Math.Round(Math.Sqrt(radicand), 2, MidpointRounding.AwayFromZero); - return true; - } - - } - - private bool TryCalculateExponent(double baseNumber, double exponent, out double result) - { - if (exponent > 10) - { - Console.WriteLine("The exponent is very big, try a smaller number"); - result = default; - return false; - } - - else - { - result = Math.Pow(baseNumber, exponent); - return true; - } - } - - private bool TryCalculateTrygonometry(double degrees, TrigonometryFunctions function, out double result) - { - if (degrees > 360 || degrees < -360) - { - Console.WriteLine("The degree value is outside of this scope, try a smaller number"); - result = default; - return false; - } - - else - { - var radians = degrees * (Math.PI / 180); - - result = function switch - { - TrigonometryFunctions.Sin => Math.Round(Math.Sin(radians), 4), - TrigonometryFunctions.Cos => Math.Round(Math.Cos(radians), 4), - TrigonometryFunctions.Tan => Math.Round(Math.Tan(radians), 4), - _ => throw new ArgumentOutOfRangeException(nameof(function)) - }; - - return true; - } - } } } diff --git a/Calculator.ivangar/CalculatorLibrary/CalculatorMath.cs b/Calculator.ivangar/CalculatorLibrary/CalculatorMath.cs new file mode 100644 index 00000000..c15f9b38 --- /dev/null +++ b/Calculator.ivangar/CalculatorLibrary/CalculatorMath.cs @@ -0,0 +1,67 @@ +using CalculatorLibrary.Enums; + +namespace CalculatorLibrary +{ + public static class CalculatorMath + { + public static bool TryDivide(double a, double b, out double result) + { + if (b == 0) + { + Console.WriteLine("Cannot divide by zero."); + result = default; + return false; + } + result = a / b; + return true; + } + + public static bool TryCalculateSquareRoot(double radicand, out double result) + { + if (radicand < 0) + { + Console.WriteLine("Cannot calculate square root of a negative number."); + result = default; + return false; + } + result = Math.Round(Math.Sqrt(radicand), 2, MidpointRounding.AwayFromZero); + return true; + } + + public static bool TryCalculateExponent(double baseNumber, double exponent, out double result) + { + result = Math.Pow(baseNumber, exponent); + + if (double.IsNaN(result) || double.IsInfinity(result)) + { + Console.WriteLine("The exponent is very big, try a smaller number"); + result = double.NaN; + return false; + } + + return true; + } + + public static bool TryCalculateTrigonometry(double degrees, TrigonometryFunctions function, out double result) + { + if (degrees > 360 || degrees < -360) + { + Console.WriteLine("The degree value is outside of this scope, try a smaller number"); + result = double.NaN; + return false; + } + + var radians = degrees * Math.PI / 180.0; + + result = function switch + { + TrigonometryFunctions.Sin => Math.Round(Math.Sin(radians), 4), + TrigonometryFunctions.Cos => Math.Round(Math.Cos(radians), 4), + TrigonometryFunctions.Tan => Math.Round(Math.Tan(radians), 4), + _ => double.NaN + }; + + return !double.IsNaN(result); + } + } +} diff --git a/Calculator.ivangar/CalculatorLibrary/OperationFactory.cs b/Calculator.ivangar/CalculatorLibrary/OperationFactory.cs new file mode 100644 index 00000000..4fceb80b --- /dev/null +++ b/Calculator.ivangar/CalculatorLibrary/OperationFactory.cs @@ -0,0 +1,20 @@ +using CalculatorLibrary.Enums; +using CalculatorLibrary.Models; + +namespace CalculatorLibrary +{ + public static class OperationFactory + { + public static MathOperation CreateBasic(double a, double b, char op, double result) => + new MathOperation { OperandA = a, OperandB = b, Operation = op, Result = result }; + + public static SquareRoot CreateSquareRoot(double radicand, char op, double result) => + new SquareRoot { Radicand = radicand, Operation = op, Result = result }; + + public static Exponentiation CreateExponentiation(double baseNumber, double exponent, char op, double result) => + new Exponentiation { Base = baseNumber, Exponent = exponent, Operation = op, Result = result }; + + public static TrigonometryOperation CreateTrigonometry(double degrees, TrigonometryFunctions function, char op, double result) => + new TrigonometryOperation { Degrees = degrees, Function = function, Operation = op, Result = result }; + } +} diff --git a/Calculator.ivangar/CalculatorLibrary/OperationRepository.cs b/Calculator.ivangar/CalculatorLibrary/OperationRepository.cs new file mode 100644 index 00000000..d417f2f5 --- /dev/null +++ b/Calculator.ivangar/CalculatorLibrary/OperationRepository.cs @@ -0,0 +1,39 @@ +using CalculatorLibrary.Models; + +namespace CalculatorLibrary +{ + public class OperationRepository + { + private readonly List _operations = new(); + + public IReadOnlyList Operations => _operations; + + public void Add(MathOperation op) + { + _operations.Add(op); + Console.WriteLine($"Operation: {op}\n"); + } + + public void Clear() => _operations.Clear(); + + public int Count => _operations.Count; + + public void PrintAll() + { + var countTimes = _operations.Count == 1 ? "time" : "times"; + Console.WriteLine($"\nThe calculator was used {_operations.Count} {countTimes}.\n"); + + if (_operations.Count == 0) + { + Console.WriteLine("\nThere are no calculations to display:\n"); + return; + } + + Console.WriteLine("Latest calculations:\n"); + foreach (var (index, operation) in _operations.Select((o, i) => (i, o))) + { + Console.WriteLine($"{index + 1}. {operation}"); + } + } + } +}