diff --git a/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector.Tests/BoringVector.Tests.csproj b/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector.Tests/BoringVector.Tests.csproj
new file mode 100644
index 00000000..6551b245
--- /dev/null
+++ b/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector.Tests/BoringVector.Tests.csproj
@@ -0,0 +1,26 @@
+
+
+
+ netcoreapp3.1
+
+ false
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+
diff --git a/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector.Tests/TestVector.cs b/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector.Tests/TestVector.cs
new file mode 100644
index 00000000..cf8aafd7
--- /dev/null
+++ b/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector.Tests/TestVector.cs
@@ -0,0 +1,60 @@
+using System;
+using Xunit;
+using BoringVector;
+
+namespace BoringVector.Tests
+{
+ public class TestVector
+ {
+ [Fact]
+ public void TestEmptyVectorLength()
+ {
+ Vector v = new Vector();
+ Assert.Equal(0.0, v.SquareLength());
+ }
+
+ [Theory]
+ [InlineData(3, 4, 25)]
+ [InlineData(5, -6, 25 + 36)]
+ public void TestVectorLength(double x, double y, double length)
+ {
+ Vector v = new Vector() { X = x, Y = y };
+ Assert.Equal(length, v.SquareLength());
+ }
+
+ [Fact]
+ public void TestVectorAdd()
+ {
+ Vector v1 = new Vector() { X = 3, Y = 4 };
+ Vector v2 = new Vector() { X = 2, Y = -2 };
+ Vector sum = v1.Add(v2);
+ Assert.Equal(5.0, sum.X);
+ Assert.Equal(2.0, sum.Y);
+ }
+
+ [Fact]
+ public void TestVectorScale()
+ {
+ Vector v = new Vector() { X = 3, Y = -4 };
+ Vector scaled = v.Scale(-2);
+ Assert.Equal(-6, scaled.X);
+ Assert.Equal(8.0, scaled.Y);
+ }
+
+ [Fact]
+ public void TestVectorDotProduct()
+ {
+ Vector v1 = new Vector() { X = 3, Y = 4 };
+ Vector v2 = new Vector() { X = 2, Y = -2 };
+ Assert.Equal(3 * 2 - 4 * 2, v1.DotProduct(v2));
+ }
+
+ [Fact]
+ public void TestVectorCrossProduct()
+ {
+ Vector v1 = new Vector() { X = 3, Y = 4 };
+ Vector v2 = new Vector() { X = 2, Y = -2 };
+ Assert.Equal(-3 * 2 - 4 * 2, v1.CrossProduct(v2));
+ }
+ }
+}
diff --git a/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector.sln b/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector.sln
index ef06cdd5..25cbbc26 100644
--- a/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector.sln
+++ b/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector.sln
@@ -1,9 +1,11 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.27004.2002
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31005.135
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BoringVector", "BoringVector\BoringVector.csproj", "{7B438112-6A12-47BC-B494-FF8850924783}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BoringVector", "BoringVector\BoringVector.csproj", "{7B438112-6A12-47BC-B494-FF8850924783}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BoringVector.Tests", "BoringVector.Tests\BoringVector.Tests.csproj", "{4E727AC5-1465-493E-9A2D-07D951651867}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -15,6 +17,10 @@ Global
{7B438112-6A12-47BC-B494-FF8850924783}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7B438112-6A12-47BC-B494-FF8850924783}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7B438112-6A12-47BC-B494-FF8850924783}.Release|Any CPU.Build.0 = Release|Any CPU
+ {4E727AC5-1465-493E-9A2D-07D951651867}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4E727AC5-1465-493E-9A2D-07D951651867}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4E727AC5-1465-493E-9A2D-07D951651867}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4E727AC5-1465-493E-9A2D-07D951651867}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector/Vector.cs b/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector/Vector.cs
index bb9db585..4edc5cf9 100644
--- a/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector/Vector.cs
+++ b/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector/Vector.cs
@@ -1,4 +1,7 @@
using System;
+using System.Runtime.CompilerServices;
+
+[assembly: InternalsVisibleTo("BoringVector.Tests")]
namespace BoringVector
{
@@ -10,55 +13,138 @@ namespace BoringVector
internal struct Vector
{
- /*
- Vector задается парой вещественных координат X и Y.
- */
-
+ ///
+ /// Координаты вектора
+ ///
+ public double X, Y;
- /*
- На месте заглушек добавь реализацию базовых методов вектора:
- - квадрат длины
- - сумма векторов
- - умножение на коэффициент
- - скалярное произведение
- - векторное произведение (= площадь параллелограмма)
- */
+ ///
+ /// Квадрат длины вектора
+ ///
+ /// квадрат длины вектора
public double SquareLength()
{
- throw new NotImplementedException();
+ return X * X + Y * Y;
}
+
+ ///
+ /// Прибавляет вектор v к данному
+ ///
+ /// Вектор, который нужно прибавать
+ /// Сумму текущего вектора с v
public Vector Add(Vector v)
{
- throw new NotImplementedException();
+ return new Vector { X = X + v.X, Y = Y + v.Y };
}
+ ///
+ /// Умножает текущий вектор на число
+ ///
+ /// Множитель
+ /// Произведение вектора на k
public Vector Scale(double k)
{
- throw new NotImplementedException();
+ return new Vector { X = X * k, Y = Y * k };
}
+ ///
+ /// Скалярное произведение вектора с v
+ ///
+ /// Второй вектор в скалярном произвдении
+ /// Число, равное скалярному произведению
public double DotProduct(Vector v)
{
- throw new NotImplementedException();
+ return X * v.X + Y * v.Y;
}
+ ///
+ /// Векторное произведение вектора с v
+ ///
+ /// Второй вектор в векторном произвдении
+ /// Число, равное Z компоненте векторномго произведения
public double CrossProduct(Vector v)
{
- throw new NotImplementedException();
+ return X * v.Y - Y * v.X;
}
- /*
- Переопредели ниже метод ToString - пусть выводит (X; Y)
- */
+ ///
+ /// Котиковое представление вектора
+ ///
+ /// Строковое представление вектора для котика
+ public override string ToString()
+ {
+ return string.Format("({0:f}; {1:f})", X, Y);
+ }
- #region operators
+ ///
+ /// Сложение двух векторов
+ ///
+ /// Вектор a
+ /// Вектор b
+ /// Вектор равный a+b
+ public static Vector operator +(Vector a, Vector b)
+ {
+ return a.Add(b);
+ }
- /*
- Реализуй также следущие операторы (Vector v, u и double k):
- - v + u, v - u
- - k * v, v * k, v / k
- - +v, -v
- */
+ ///
+ /// Вычитание двух векторов
+ ///
+ /// Вектор a
+ /// Вектор b
+ /// Вектор равный a-b
+ public static Vector operator -(Vector a, Vector b)
+ {
+ return new Vector { X = a.X - b.X, Y = a.Y - b.Y };
+ }
+
+ ///
+ /// Умножение вектора на число
+ ///
+ /// Вектор
+ /// Число
+ /// Вектор равный a*k
+ public static Vector operator *(Vector a, double k)
+ {
+ return a.Scale(k);
+ }
+
+ ///
+ /// Умножение вектора на число
+ ///
+ /// Число
+ /// Вектор
+ /// Вектор равный k*a
+ public static Vector operator *(double k, Vector a)
+ {
+ return a.Scale(k);
+ }
+
+ ///
+ /// Деление вектора на число
+ ///
+ /// Вектор
+ /// Число, не должно быть нулем
+ /// Вектор равный a/k
+ public static Vector operator /(Vector a, double k)
+ {
+ return a.Scale(checked(1 / k));
+ }
+
+
+ ///
+ /// Вектор, обратный данному
+ ///
+ /// Вектор
+ /// Вектор равный -a
+ public static Vector operator -(Vector a)
+ {
+ return a.Scale(-1);
+ }
+
+ public static Vector operator +(Vector a)
+ {
+ return a;
+ }
- #endregion
}
#endregion
@@ -110,6 +196,7 @@ public double CrossProduct(Vector v)
Правилом хорошего тона считается писать комментарии к методам, классам и другим сущностям, используя данный синтаксис - так ты и комментируешь их, и документируешь.
Внутри методов он не поддерживается, поэтому там только обычные (// или /*).
+
Ниже приведены примеры простейших комментариев. Если наведете мышкой на название метода DoNothing, увидишь,
что студия отображает комментарий в подписи (в других IDE из коробки без плагинов это вряд ли будет работать).
Если навести на аргумент метода DoNothing - something, увидишь комментарий к нему.
@@ -174,6 +261,7 @@ public static void ThrowNotImplementedException()
Особо не заморачивайся с тем, чтобы оттестировать все возможные специальные случаи - в данном задании важно, чтобы
ты просто разобрался(-ась), как писать автотесты и как их запускать. Это задание НЕ на то, как писать хорошие тесты.
+
Примечание: структура Vector описана как internal структура, поэтому по умолчанию сборке BoringVector.Tests она не видна.
Чтобы она была видна, существует специальная директива компилятору:
[assembly: InternalsVisibleTo("XXX")]
@@ -186,8 +274,7 @@ public static void ThrowNotImplementedException()
#endregion
-
/*
На этом все. Время делать пулл реквест и наслаждаться заслуженным отдыхом :)
*/
-}
+}
\ No newline at end of file
diff --git a/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector/VectorExtensions.cs b/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector/VectorExtensions.cs
index 525be40f..a5e3ec2e 100644
--- a/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector/VectorExtensions.cs
+++ b/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector/VectorExtensions.cs
@@ -1,4 +1,6 @@
-namespace BoringVector
+using System;
+
+namespace BoringVector
{
/*
Здесь тебе нужно написать класс с методами-расширениями структуры Vector:
@@ -7,4 +9,57 @@
- GetAngleBetween: возвращает угол между двумя векторами в радианах. Примечание: нулевой вектор сонаправлен любому другому.
- GetRelation: возвращает значение перечесления VectorRelation(General, Parallel, Orthogonal) - отношение между двумя векторами("общий случай", параллельны, перпендикулярны). Перечисление задавать тоже тебе)
*/
+
+
+ internal enum VectorRelation
+ {
+ General,
+ Parallel,
+ Orthogonal
+ }
+
+ internal static class VectorExtention
+ {
+ private const double Epsilon = 1e-6;
+
+ internal static bool IsZero(this Vector v)
+ {
+ return Math.Abs(v.X) < Epsilon && Math.Abs(v.Y) < Epsilon;
+ }
+
+ internal static Vector Normalize(this Vector v)
+ {
+ return v / Math.Sqrt(v.SquareLength());
+ }
+
+ internal static double GetAngleBetween(this Vector a, Vector b)
+ {
+ if (a.IsZero() || b.IsZero())
+ {
+ return 0;
+ }
+ return Math.Acos(a.DotProduct(b) / Math.Sqrt(a.SquareLength() * b.SquareLength()));
+ }
+
+ internal static VectorRelation GetRelation(this Vector a, Vector b)
+ {
+ double angle = a.GetAngleBetween(b);
+ if (Math.Abs(angle - Math.PI) < Epsilon)
+ {
+ return VectorRelation.Orthogonal;
+ }
+ else
+ {
+ if (angle < Epsilon || angle > Math.PI + Epsilon)
+ {
+ return VectorRelation.Parallel;
+ }
+ else
+ {
+ return VectorRelation.General;
+ }
+ }
+ }
+ }
+
}