diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..e7e7cb3 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,6 @@ +image: Visual Studio 2019 + +build_script: + - For /R %%I in (*.sln) do dotnet test %%I + +test: off \ No newline at end of file diff --git a/hw2Calculator/hw2Calculator.Test/CalculatorTest.cs b/hw2Calculator/hw2Calculator.Test/CalculatorTest.cs new file mode 100644 index 0000000..aa328e0 --- /dev/null +++ b/hw2Calculator/hw2Calculator.Test/CalculatorTest.cs @@ -0,0 +1,71 @@ +using NUnit.Framework; +using System.Collections.Generic; +using System; +using System.Linq; + +namespace Hw2Calculator.Test +{ + public class CalculatorTests + { + private bool CheckTrueExpression(bool isCorrect, double result, double mainResult) + { + return !isCorrect || Math.Abs(result - mainResult) < 0.000001; + } + + private static (string Test, double Result)[] correctDataForTests = new[] + { + ("2 4 * 2 -", 6.0), + ("2 2 +", 4.0), + ("16 5 -", 11.0), + ("5 5 *", 25.0), + ("5 -5 *", -25.0), + ("-5 -5 *", 25), + ("25 5 /", 5), + ("25 -5 /", -5), + ("-25 -5 /", 5), + ("-25 -5 /", 5), + ("-25 -5 /", 5), + ("1 2 + 5 2 - *", 9), + ("6 3 - 1 2 * /", 1.5), + }; + + [TestCaseSource(nameof(TestCorrectData))] + public void CalculatorTestForCorrectData(IStack stack, string expresion, double mainResult) + { + (var result, var isCorrect) = Calculator.CalculatorExpression(expresion, stack); + Assert.IsTrue(CheckTrueExpression(isCorrect, result, mainResult)); + } + + private static IEnumerable TestCorrectData + => + correctDataForTests.SelectMany(DataForTests => new TestCaseData[] + { + new TestCaseData(new StackList(), DataForTests.Test, DataForTests.Result), + new TestCaseData(new StackArray(), DataForTests.Test, DataForTests.Result) + }); + + private static (string Test, double Result)[] incorrectDataForTests = new[] + { + ("2 + 2", 0.0), + ("2 / 0", 0.0), + ("2 +", 0.0), + ("2 asd", 0.0), + ("2 2 + 2", 0.0), + }; + + [TestCaseSource(nameof(TestIncorrectDate))] + public void CalculatorTestForIncorrectData(IStack stack, string expresion, double mainResult) + { + (var result, var isCorrect) = Calculator.CalculatorExpression(expresion, stack); + Assert.IsTrue(CheckTrueExpression(isCorrect, result, mainResult)); + } + + private static IEnumerable TestIncorrectDate + => + incorrectDataForTests.SelectMany(DataForTests => new TestCaseData[] + { + new TestCaseData(new StackList(), DataForTests.Test, DataForTests.Result), + new TestCaseData(new StackArray(), DataForTests.Test, DataForTests.Result) + }); + } +} \ No newline at end of file diff --git a/hw2Calculator/hw2Calculator.Test/IStackTest.cs b/hw2Calculator/hw2Calculator.Test/IStackTest.cs new file mode 100644 index 0000000..0330d97 --- /dev/null +++ b/hw2Calculator/hw2Calculator.Test/IStackTest.cs @@ -0,0 +1,48 @@ +using NUnit.Framework; +using System.Collections.Generic; + +namespace Hw2Calculator.Test +{ + [TestFixture] + public class IStackTest + { + [TestCaseSource(nameof(Stacks))] + public void IsEmptyAfterPush(IStack stack) + { + stack.Push(9); + Assert.IsTrue(!(stack.IsEmpty())); + } + + [TestCaseSource(nameof(Stacks))] + public void PopAfterPush(IStack stack) + { + stack.Push(9); + Assert.AreEqual(9, stack.Pop()); + } + + [TestCaseSource(nameof(Stacks))] + public void CheckDeleteStack(IStack stack) + { + stack.Push(9); + stack.Push(8); + stack.Push(9); + stack.ClearStack(); + Assert.IsTrue((stack.IsEmpty())); + } + + [TestCaseSource(nameof(Stacks))] + public void CheckIsEmpty(IStack stack) + { + stack.Push(9); + stack.Pop(); + Assert.IsTrue((stack.IsEmpty())); + } + + private static IEnumerable Stacks + => new TestCaseData[] + { + new TestCaseData(new StackList()), + new TestCaseData(new StackArray()), + }; + } +} \ No newline at end of file diff --git a/hw2Calculator/hw2Calculator.Test/hw2Calculator.Test.csproj b/hw2Calculator/hw2Calculator.Test/hw2Calculator.Test.csproj new file mode 100644 index 0000000..57c346a --- /dev/null +++ b/hw2Calculator/hw2Calculator.Test/hw2Calculator.Test.csproj @@ -0,0 +1,19 @@ + + + + netcoreapp3.1 + + false + + + + + + + + + + + + + diff --git a/hw2Calculator/hw2Calculator.sln b/hw2Calculator/hw2Calculator.sln new file mode 100644 index 0000000..b1573bc --- /dev/null +++ b/hw2Calculator/hw2Calculator.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31005.135 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hw2Calculator", "hw2Calculator\Hw2Calculator.csproj", "{6910FA32-065A-451E-93C8-D690BA4C486A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "hw2Calculator.Test", "hw2Calculator.Test\hw2Calculator.Test.csproj", "{9AB5D195-767E-4A4A-BCC8-66536BBE511F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6910FA32-065A-451E-93C8-D690BA4C486A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6910FA32-065A-451E-93C8-D690BA4C486A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6910FA32-065A-451E-93C8-D690BA4C486A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6910FA32-065A-451E-93C8-D690BA4C486A}.Release|Any CPU.Build.0 = Release|Any CPU + {9AB5D195-767E-4A4A-BCC8-66536BBE511F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9AB5D195-767E-4A4A-BCC8-66536BBE511F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9AB5D195-767E-4A4A-BCC8-66536BBE511F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9AB5D195-767E-4A4A-BCC8-66536BBE511F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {851B8E89-996A-4A60-A0E1-8BC3BA05EEFB} + EndGlobalSection +EndGlobal diff --git a/hw2Calculator/hw2Calculator/Calculator.cs b/hw2Calculator/hw2Calculator/Calculator.cs new file mode 100644 index 0000000..843ead8 --- /dev/null +++ b/hw2Calculator/hw2Calculator/Calculator.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Hw2Calculator +{ + public static class Calculator + { + public static (double, bool) CalculatorExpression(string expression, IStack stack) + { + string number = ""; + char[] expressionArray = expression.ToCharArray(0, expression.Length); + for (int i = 0; i < expression.Length; ++i) + { + if (expressionArray[i] == ' ') + { + number = ""; + continue; + } + if (Char.IsDigit(expressionArray[i])) + { + while (i < expression.Length && expressionArray[i] != ' ') + { + number += expressionArray[i]; + ++i; + } + stack.Push(double.Parse(number)); + number = ""; + continue; + } + if (IsOperator(expressionArray[i])) + { + if (stack.IsEmpty()) + { + return (0, false); + } + double lastNumber = stack.Pop(); + if (stack.IsEmpty() || (expressionArray[i] == '/' && Math.Abs(lastNumber - 0) < 0.00001)) + { + stack.ClearStack(); + return (0, false); + } + stack.Push(lastNumber); + ArithmeticOperation(expressionArray[i], stack); + } + else + { + stack.ClearStack(); + return (0, false); + } + } + if (stack.IsEmpty()) + { + return (0, false); + } + var result = stack.Pop(); + if (stack.IsEmpty()) + { + return (result, true); + } + stack.ClearStack(); + return (0, false); + } + + private static bool IsOperator(char symbol) + => symbol == '+' || symbol == '-' || symbol == '*' || symbol == '/'; + + private static void ArithmeticOperation(char operation, IStack stack) + { + var number2 = stack.Pop(); + var number1 = stack.Pop(); + switch (operation) + { + case '+': + stack.Push(number1 + number2); + break; + case '-': + stack.Push(number1 - number2); + break; + case '*': + stack.Push(number1 * number2); + break; + case '/': + stack.Push(number1 / number2); + break; + } + } + } +} diff --git a/hw2Calculator/hw2Calculator/IStack.cs b/hw2Calculator/hw2Calculator/IStack.cs new file mode 100644 index 0000000..7ac5915 --- /dev/null +++ b/hw2Calculator/hw2Calculator/IStack.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Hw2Calculator +{ + public interface IStack + { + void Push(double value); + + double Pop(); + + bool IsEmpty(); + + void ClearStack(); + } +} \ No newline at end of file diff --git a/hw2Calculator/hw2Calculator/Program.cs b/hw2Calculator/hw2Calculator/Program.cs new file mode 100644 index 0000000..4a3c7ff --- /dev/null +++ b/hw2Calculator/hw2Calculator/Program.cs @@ -0,0 +1,43 @@ +using System; + +namespace Hw2Calculator +{ + class Program + { + static void Main() + { + Console.WriteLine("Меню:"); + Console.WriteLine("1 - стэк на списках."); + Console.WriteLine("2 - стэк на массиве."); + Console.WriteLine("Ваш выбор:"); + var str = Console.ReadLine(); + if (!int.TryParse(str, out int choice)) + { + Console.WriteLine("Ошибка ввода!"); + return; + } + IStack stack; + switch (choice) + { + case 1: + stack = new StackList(); + break; + case 2: + stack = new StackArray(); + break; + default: + Console.WriteLine("Ошибка ввода!"); + return; + } + Console.WriteLine("Введите выражение в постфиксной форме: "); + string expression = Console.ReadLine(); + (var result, var isCorrect) = Calculator.CalculatorExpression(expression, stack); + if (!isCorrect) + { + Console.WriteLine("Ошибка ввода!"); + return; + } + Console.WriteLine("Ответ: " + result); + } + } +} \ No newline at end of file diff --git a/hw2Calculator/hw2Calculator/StackArray.cs b/hw2Calculator/hw2Calculator/StackArray.cs new file mode 100644 index 0000000..2578a1d --- /dev/null +++ b/hw2Calculator/hw2Calculator/StackArray.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Hw2Calculator +{ + public class StackArray : IStack + { + private double[] stackElements; + private int countNumbersInStack; + + public StackArray() + { + stackElements = new double[5]; + } + + public void Push(double value) + { + if (countNumbersInStack == stackElements.Length) + { + Array.Resize(ref stackElements, stackElements.Length * 2); + } + stackElements[countNumbersInStack] = value; + countNumbersInStack++; + } + + public double Pop() + { + if (IsEmpty()) + { + throw new InvalidOperationException(); + } + countNumbersInStack--; + return stackElements[countNumbersInStack]; + } + + public bool IsEmpty() + => countNumbersInStack == 0; + + public void ClearStack() + { + stackElements = new double[5]; + countNumbersInStack = 0; + } + } +} \ No newline at end of file diff --git a/hw2Calculator/hw2Calculator/StackList.cs b/hw2Calculator/hw2Calculator/StackList.cs new file mode 100644 index 0000000..929dfc5 --- /dev/null +++ b/hw2Calculator/hw2Calculator/StackList.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Hw2Calculator +{ + public class StackList : IStack + { + private class StackElement + { + public double value; + public StackElement next; + } + + private StackElement head; + + public void Push(double value) + => head = new StackElement() { value = value, next = head }; + + public double Pop() + { + if (IsEmpty()) + { + throw new InvalidOperationException(); + } + double answer = head.value; + head = head.next; + return answer; + } + + public bool IsEmpty() + => head == null; + + public void ClearStack() + => head = null; + } +} \ No newline at end of file diff --git a/hw2Calculator/hw2Calculator/hw2Calculator.csproj b/hw2Calculator/hw2Calculator/hw2Calculator.csproj new file mode 100644 index 0000000..c73e0d1 --- /dev/null +++ b/hw2Calculator/hw2Calculator/hw2Calculator.csproj @@ -0,0 +1,8 @@ + + + + Exe + netcoreapp3.1 + + +