diff --git a/C#/forSpbu/Calculator/Calculator.csproj b/C#/forSpbu/Calculator/Calculator.csproj
new file mode 100644
index 0000000..f4dc8b5
--- /dev/null
+++ b/C#/forSpbu/Calculator/Calculator.csproj
@@ -0,0 +1,12 @@
+
+
+
+ WinExe
+ net7.0-windows
+ enable
+ true
+ enable
+ true
+
+
+
\ No newline at end of file
diff --git a/C#/forSpbu/Calculator/Calculator.csproj.user b/C#/forSpbu/Calculator/Calculator.csproj.user
new file mode 100644
index 0000000..3a34caa
--- /dev/null
+++ b/C#/forSpbu/Calculator/Calculator.csproj.user
@@ -0,0 +1,8 @@
+
+
+
+
+ Form
+
+
+
\ No newline at end of file
diff --git a/C#/forSpbu/Calculator/CalculatorCore.cs b/C#/forSpbu/Calculator/CalculatorCore.cs
new file mode 100644
index 0000000..13acf3b
--- /dev/null
+++ b/C#/forSpbu/Calculator/CalculatorCore.cs
@@ -0,0 +1,277 @@
+namespace Calculator;
+
+public class CalculatorCore
+{
+ private enum Operation
+ {
+ Add,
+ Sub,
+ Mul,
+ Div,
+ Mod,
+ Clear,
+ Equal,
+ None
+ }
+
+ private enum State
+ {
+ FirstOperandNumber,
+ FirstOperandComma,
+ SecondOperandNumber,
+ SecondOperandComma,
+ Operation,
+ Error,
+ None
+ }
+
+ private Operation StringGetOperation(string operationString)
+ {
+ return operationString switch
+ {
+ "+" => Operation.Add,
+ "-" => Operation.Sub,
+ "*" => Operation.Mul,
+ "/" => Operation.Div,
+ "mod" => Operation.Mod,
+ "C" => Operation.Clear,
+ "=" => Operation.Equal,
+ _ => throw new ArgumentOutOfRangeException(nameof(operationString), operationString, null)
+ };
+ }
+
+ public void TakeNumberToken(string numberString)
+ {
+ if (numberString is not ("0" or "1" or "2" or "3" or "4" or "5" or "6" or "7" or "8" or "9" or ","))
+ {
+ throw new ArgumentOutOfRangeException(nameof(numberString), numberString, null);
+ }
+
+ switch (_state)
+ {
+ case State.Error:
+ if (numberString != ",")
+ {
+ _number = numberString;
+ Expression = "";
+ _state = State.FirstOperandNumber;
+ }
+ break;
+ case State.FirstOperandComma:
+ if (numberString == ",")
+ {
+ _state = State.Error;
+ break;
+ }
+
+ _number += numberString;
+ _state = State.FirstOperandNumber;
+ break;
+ case State.FirstOperandNumber:
+ if (_hasComma && numberString == ",")
+ {
+ _state = State.Error;
+ break;
+ }
+
+ if (numberString == ",")
+ {
+ _hasComma = true;
+ }
+ _number += numberString;
+ break;
+ case State.SecondOperandComma:
+ if (numberString == ",")
+ {
+ _state = State.Error;
+ break;
+ }
+
+ _number += numberString;
+ _state = State.SecondOperandNumber;
+ break;
+ case State.SecondOperandNumber:
+ if (_hasComma && numberString == ",")
+ {
+ _state = State.Error;
+ break;
+ }
+
+ _hasComma = numberString == ",";
+ _number += numberString;
+ break;
+ case State.Operation:
+ if (numberString == ",")
+ {
+ _state = State.Error;
+ break;
+ }
+
+ _number = numberString;
+ if (_operation == Operation.Equal)
+ {
+ _operation = Operation.None;
+ Expression = "";
+ _state = State.FirstOperandNumber;
+ break;
+ }
+
+ _state = State.SecondOperandNumber;
+ break;
+ case State.None:
+ if (numberString == ",")
+ {
+ _number += numberString;
+ _state = State.FirstOperandComma;
+ _hasComma = true;
+ }
+ else
+ {
+ _number = numberString;
+ _state = State.FirstOperandNumber;
+ }
+
+ Expression = "";
+
+ break;
+ }
+
+ if (_state == State.Error)
+ {
+ Expression = "";
+ _number = "Error";
+ _hasComma = false;
+ }
+ }
+
+ private void ApplyOperation()
+ {
+ switch (_operation)
+ {
+ case Operation.Add:
+ _firstOperand += _secondOperand;
+ break;
+ case Operation.Sub:
+ _firstOperand -= _secondOperand;
+ break;
+ case Operation.Mul:
+ _firstOperand *= _secondOperand;
+ break;
+ case Operation.Div:
+ if (_secondOperand is < Delta and > -Delta)
+ {
+ _state = State.Error;
+ break; // Можно как фишку оставить, будет бесконечность
+ }
+ _firstOperand /= _secondOperand;
+ break;
+ case Operation.Mod:
+ if (_secondOperand is < Delta and > -Delta)
+ {
+ _state = State.Error;
+ break;
+ }
+ _firstOperand %= _secondOperand;
+ break;
+ }
+ }
+
+ public void TakeOperationToken(string operationString)
+ {
+ var operation = StringGetOperation(operationString);
+ if (operation == Operation.Clear)
+ {
+ _state = State.None;
+ _operation = Operation.None;
+ Expression = "";
+ _number = "0";
+ _hasComma = false;
+ return;
+ }
+
+ switch (_state)
+ {
+ case State.Error:
+ break;
+ case State.FirstOperandComma:
+ _state = State.Operation;
+ _number = _number.Remove(_number.Length - 1);
+
+ if (!double.TryParse(_number, out _firstOperand))
+ {
+ throw new ArgumentOutOfRangeException(nameof(_number), _number, null);;
+ }
+
+ _operation = operation;
+ Expression = _firstOperand + " " + operationString;
+ break;
+ case State.FirstOperandNumber:
+ _state = State.Operation;
+ if (!double.TryParse(_number, out _firstOperand))
+ {
+ throw new ArgumentOutOfRangeException(nameof(_number), _number, null);;
+ }
+
+ _operation = operation;
+ Expression = _firstOperand + " " + operationString;
+ break;
+ case State.SecondOperandComma:
+ _state = State.Operation;
+ _number = _number.Remove(_number.Length - 1);
+ if (!double.TryParse(_number, out _secondOperand))
+ {
+ throw new ArgumentOutOfRangeException(nameof(_number), _number, null);
+ }
+
+ ApplyOperation();
+ _operation = operation;
+
+ Expression = _firstOperand + " " + operationString;
+ _hasComma = false;
+ _number = "";
+
+ break;
+ case State.SecondOperandNumber:
+ _state = State.Operation;
+ if (!double.TryParse(_number, out _secondOperand))
+ {
+ throw new ArgumentOutOfRangeException(nameof(_number), _number, null);
+ }
+
+ ApplyOperation();
+ _operation = operation;
+
+ Expression = _firstOperand + " " + operationString;
+ _hasComma = false;
+ _number = "";
+
+ break;
+ case State.Operation:
+ _operation = operation;
+ Expression = _firstOperand + " " + operationString;
+ break;
+ case State.None:
+ _state = State.Operation;
+ _operation = operation;
+ Expression = "0 " + operationString;
+ break;
+ }
+
+ if (_state == State.Error)
+ {
+ Expression = "";
+ _number = "Error";
+ }
+ }
+
+ private double _firstOperand = 0;
+ private double _secondOperand = 0;
+ private Operation _operation = Operation.None;
+ private State _state = State.None;
+ private string _number = "0";
+ private bool _hasComma = false;
+ private const double Delta = 0.0001;
+
+ public string Number => _number;
+ public string Expression { get; private set; } = "";
+}
\ No newline at end of file
diff --git a/C#/forSpbu/Calculator/CalculatorForm.Designer.cs b/C#/forSpbu/Calculator/CalculatorForm.Designer.cs
new file mode 100644
index 0000000..2756b03
--- /dev/null
+++ b/C#/forSpbu/Calculator/CalculatorForm.Designer.cs
@@ -0,0 +1,182 @@
+namespace Calculator;
+
+partial class CalculatorForm
+{
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ mainLayout = new TableLayoutPanel();
+
+ expression = new Label();
+ numberLabel = new Label();
+ buttonsTable = new TableLayoutPanel();
+
+ for (int i = 0; i <= 10; i++)
+ {
+ numberButtons.Add(new Button());
+ }
+ for (int i = 0; i < 7; i++)
+ {
+ operationButtons.Add(new Button());
+ }
+ string[] operationsText = { "C", "+", "-", "mod", "*", "/", "=" };
+
+
+ buttonsTable.SuspendLayout();
+ mainLayout.SuspendLayout();
+ SuspendLayout();
+
+
+ /*
+ * Calculator form
+ */
+ Size = new Size(400, 400);
+ MinimumSize = new Size(300, 400);
+ Text = "Calculator";
+ Controls.Add(mainLayout);
+
+ /*
+ * Main label
+ */
+ mainLayout.Size = new Size(385, 362);
+ mainLayout.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top;
+ mainLayout.ColumnCount = 1;
+ mainLayout.RowCount = 3;
+ mainLayout.Controls.Add(expression, 0, 0);
+ mainLayout.Controls.Add(numberLabel, 0, 1);
+ mainLayout.Controls.Add(buttonsTable, 0, 2);
+ mainLayout.RowStyles.Add(new ColumnStyle(SizeType.Percent, 10F));
+ mainLayout.RowStyles.Add(new ColumnStyle(SizeType.Percent, 15F));
+ mainLayout.RowStyles.Add(new ColumnStyle(SizeType.Percent, 75F));
+
+ /*
+ * Expression label
+ */
+ expression.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top;
+ expression.TextAlign = ContentAlignment.MiddleRight;
+ expression.Font = new Font("Segoe UI", 15F, FontStyle.Regular, GraphicsUnit.Pixel);
+ expression.Text = "";
+
+ /*
+ * Number label
+ */
+ numberLabel.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top;
+ numberLabel.TextAlign = ContentAlignment.MiddleRight;
+ numberLabel.Font = new Font("Segoe UI", 30F, FontStyle.Regular, GraphicsUnit.Pixel);
+ numberLabel.Text = "0";
+
+ /*
+ * Buttons table
+ */
+ buttonsTable.BackColor = Color.Black;
+ buttonsTable.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top;
+ buttonsTable.ColumnCount = 3;
+ buttonsTable.RowCount = 6;
+ buttonsTable.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100/buttonsTable.ColumnCount));
+ buttonsTable.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100/buttonsTable.ColumnCount));
+ buttonsTable.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100/buttonsTable.ColumnCount));
+ buttonsTable.RowStyles.Add(new ColumnStyle(SizeType.Percent, 100/buttonsTable.RowCount));
+ buttonsTable.RowStyles.Add(new ColumnStyle(SizeType.Percent, 100/buttonsTable.RowCount));
+ buttonsTable.RowStyles.Add(new ColumnStyle(SizeType.Percent, 100/buttonsTable.RowCount));
+ buttonsTable.RowStyles.Add(new ColumnStyle(SizeType.Percent, 100/buttonsTable.RowCount));
+ buttonsTable.RowStyles.Add(new ColumnStyle(SizeType.Percent, 100/buttonsTable.RowCount));
+ buttonsTable.RowStyles.Add(new ColumnStyle(SizeType.Percent, 100/buttonsTable.RowCount));
+ buttonsTable.Controls.Add(numberButtons[0], 1, 5);
+ buttonsTable.Controls.Add(numberButtons[1], 0, 4);
+ buttonsTable.Controls.Add(numberButtons[2], 1, 4);
+ buttonsTable.Controls.Add(numberButtons[3], 2, 4);
+ buttonsTable.Controls.Add(numberButtons[4], 0, 3);
+ buttonsTable.Controls.Add(numberButtons[5], 1, 3);
+ buttonsTable.Controls.Add(numberButtons[6], 2, 3);
+ buttonsTable.Controls.Add(numberButtons[7], 0, 2);
+ buttonsTable.Controls.Add(numberButtons[8], 1, 2);
+ buttonsTable.Controls.Add(numberButtons[9], 2, 2);
+ buttonsTable.Controls.Add(operationButtons[0], 0, 0);
+ buttonsTable.Controls.Add(operationButtons[1], 1, 0);
+ buttonsTable.Controls.Add(operationButtons[2], 2, 0);
+ buttonsTable.Controls.Add(operationButtons[3], 0, 1);
+ buttonsTable.Controls.Add(operationButtons[4], 1, 1);
+ buttonsTable.Controls.Add(operationButtons[5], 2, 1);
+ buttonsTable.Controls.Add(operationButtons[6], 2, 5);
+
+ buttonsTable.Controls.Add(numberButtons[10], 0, 5);
+
+ /*
+ * Buttons
+ */
+ for (int i = 0; i <= 9; i++)
+ {
+ var button = numberButtons[i];
+ button.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top;
+ button.BackColor = Color.Gray;
+ button.TextAlign = ContentAlignment.MiddleCenter;
+ button.Text = i.ToString();
+ button.ForeColor = Color.Azure;
+ button.Font = new Font("Segoe UI", 15F, FontStyle.Regular, GraphicsUnit.Pixel);
+ button.Click += NumberOnClick;
+ }
+ var commaButton = numberButtons[10];
+ commaButton.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top;
+ commaButton.BackColor = Color.DimGray;
+ commaButton.TextAlign = ContentAlignment.MiddleCenter;
+ commaButton.Text = ",";
+ commaButton.ForeColor = Color.Azure;
+ commaButton.Font = new Font("Segoe UI", 15F, FontStyle.Regular, GraphicsUnit.Pixel);
+ commaButton.Click += NumberOnClick;
+
+ /*
+ * Operations
+ */
+ for (int i = 0; i < 7; i++)
+ {
+ var button = operationButtons[i];
+ button.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top;
+ button.BackColor = (operationsText[i] != "=") ? Color.DimGray : Color.Aqua;
+ button.TextAlign = ContentAlignment.MiddleCenter;
+ button.Text = operationsText[i];
+ button.ForeColor = (operationsText[i] != "=") ? Color.Azure : Color.Black;
+ button.Font = new Font("Segoe UI", 15F, FontStyle.Regular, GraphicsUnit.Pixel);
+ button.Click += OperationOnClick;
+ }
+
+
+ buttonsTable.ResumeLayout(false);
+ mainLayout.ResumeLayout(false);
+ ResumeLayout(false);
+ }
+
+ #endregion
+
+ private TableLayoutPanel mainLayout;
+
+ private Label expression;
+ private Label numberLabel;
+ private TableLayoutPanel buttonsTable;
+
+ private List