From 8a52269e7c25c8d231bb46e8e347746da35655df Mon Sep 17 00:00:00 2001 From: Jeremy Date: Tue, 18 May 2021 17:06:48 +0300 Subject: [PATCH 1/4] TASK 1 - Both parts of Task 1: Primitive types done. --- .../Numbers/FloatNumbers.cs | 34 ++++++++++++++++--- .../01-primitive-types/Numbers/Integers.cs | 31 ++++++++++++----- 2 files changed, 52 insertions(+), 13 deletions(-) diff --git a/course-2021-1/exercises/01-primitive-types/Numbers/FloatNumbers.cs b/course-2021-1/exercises/01-primitive-types/Numbers/FloatNumbers.cs index 9cb1d053..dcfc2905 100644 --- a/course-2021-1/exercises/01-primitive-types/Numbers/FloatNumbers.cs +++ b/course-2021-1/exercises/01-primitive-types/Numbers/FloatNumbers.cs @@ -17,7 +17,7 @@ internal static double GetNaN() Необходимо вернуть значение, не используя непосредственно саму константу. Для этого подумай, какой смысл в себе несет эта константа и где бы она могла стать результатом операции или вычисления функции. */ - throw new NotImplementedException(); + return 0.0 / 0.0; } /// @@ -28,20 +28,46 @@ internal static double GetNaN() internal static bool IsNaN(double d) { // Подсказка: по аналогии с константами типа int, у типа double тоже есть свой набор констант. - throw new NotImplementedException(); + + /* + * Разве использование + * ```cs + * return (d == Double.NaN); + * ``` + * не является некорректным? + */ + return Double.IsNaN(d); } /// /// Возвращает результат сравнения двух вещественнозначных чисел. /// /// -1 - первое меньше второго, 0 - значения равны, 1 - первое больше второго. - internal static int Compare(/* дополни сигнатуру метода как считаешь правильным */) + internal static int Compare(double a, double b) { /* Подумай, почему это задание дано в части про вещественнозначные числа. И почему не дана полная сигнатура метода. Если сходу идей нет, перестань искать подвох и просто реализуй дословно. Теперь еще раз посмотри на код и подумай в чем может быть проблема, сколько должно быть аргументов. */ - throw new NotImplementedException(); + + /* + * Не уверен, но могу предложить два объяснения: + * - Проблемы с равенством чисел с плавающей точкой - из-за погрешности равенство может не быть достигнуто. + * В таком случае можно использовать `decimal`, но поскольку условие задания сформулировано как работа именно + * с `double`, я всё-таки поставил в сигнатуре `double`. + * - Неочевидтное поведение сравнений крайних значений. Например, `(0 / 0.0) == Double.NaN`, насколько я понял, + * возвращает `false`. У `Int32` таких значений нет. + */ + if (a.Equals(b)) + { + return 0; + } else if (a < b) + { + return -1; + } else + { + return 1; + } } // и все?!! О_о diff --git a/course-2021-1/exercises/01-primitive-types/Numbers/Integers.cs b/course-2021-1/exercises/01-primitive-types/Numbers/Integers.cs index b1d90398..225d7bb0 100644 --- a/course-2021-1/exercises/01-primitive-types/Numbers/Integers.cs +++ b/course-2021-1/exercises/01-primitive-types/Numbers/Integers.cs @@ -25,6 +25,11 @@ _Хозяйке на заметку_ * throw new NotImplementedException() - твой бро. Как думаешь, почему? + +* -Чтобы было проще обнаружить источник багов, обусловленных поведением программыб которое кажется нормальным, +* а на самом деле вместо правильных значений в неимплементированных методах возвращается, например, -1, +* а не исключение. + */ using System; @@ -44,9 +49,9 @@ internal static int HalfIntMaxValue() /* После C++ вы будете приятно удивлены какое умное в .Net автодополнение (IntelliSense). Особенно это касается связки Visual Studio + Resharper, используя которую, если просто набрать return и нажать пробел, - то в появившемся списке автодополнения одной из первых будет нужная тебе константа :) + то в появившемся списке автодополнения одной из первых будет нужная тебе константа :) */ - throw new NotImplementedException(); + return Int32.MaxValue / 2; } /// @@ -55,7 +60,7 @@ internal static int HalfIntMaxValue() internal static int Cube(int x) { // не сомневайся, пиши. Тут без подвохов. - throw new NotImplementedException(); + return x * x * x; } /// @@ -66,8 +71,12 @@ internal static int CubeWithOverflowCheck(int x) /* Если спал на лекции, то тут придется погуглить, сорри. И заодно подумай какой режим выставлен по умолчанию. Почему. И почему категорически нельзя надеяться на режим по умолчанию. + * + * По умолчанию chekced не используется, так как это быстрее. Если про это забывать, то переполнение легко не заметить, + * так как исключений не будет, а значения неправильные. + * */ - throw new NotImplementedException(); + return checked(x * x * x); } /// @@ -76,7 +85,11 @@ И заодно подумай какой режим выставлен по у internal static int CubeWithoutOverflowCheck(int x) { // если сделал предыдущие, то с этим уже должно быть понятно. - throw new NotImplementedException(); + + /* + * Не очень понятно отличие от метода `int Cube(int x)` + */ + return x * x * x; } /// @@ -93,7 +106,7 @@ internal static string ToString(int x) Подсказка: нужно воспользоваться методом, который есть у абсолютно всех объектов. */ - throw new NotImplementedException(); + return x.ToString(); } /// @@ -107,7 +120,7 @@ internal static int Parse(string s) Продолжай идти простым путем -нужен метод, обратный методу ToString выше, который распарсит дефолтное строковое представление числа. Подсказка: у каждого примитивного типа есть набор статических методов, среди которых есть нужный. */ - throw new NotImplementedException(); + return Int32.Parse(s); } /// @@ -119,7 +132,7 @@ internal static int TenTimes(int x) Реализуй умножение числа на 10 без использования арифметических операций над числами. Воспользуйся реализованными выше методами ToString и Parse. И не думай ни о каких переполнениях - задача не на это :) */ - throw new NotImplementedException(); + return Int32.Parse(x.ToString() + "0"); } /// @@ -133,7 +146,7 @@ internal static string ToHexString(int x) У метода ToString числовых типов есть перегрузка, которая принимает строку с одним из заданного набора форматов. В студии дается хорошая и понятная подсказка с этим набором форматов, в других же IDE скорее всего такого не будет, и придется погуглить форматы. */ - throw new NotImplementedException(); + return x.ToString("X"); } /* From 013be3e9f263a311e1d1716bf7746b259b18561d Mon Sep 17 00:00:00 2001 From: Jeremy Date: Tue, 18 May 2021 20:31:53 +0300 Subject: [PATCH 2/4] TASK 2 - Done Task 2: Adventure Time --- .../AdventureTime/AdventureTime/Time.cs | 74 +++++++++++++++---- 1 file changed, 59 insertions(+), 15 deletions(-) diff --git a/course-2021-1/exercises/02-adventure-time/AdventureTime/AdventureTime/Time.cs b/course-2021-1/exercises/02-adventure-time/AdventureTime/AdventureTime/Time.cs index 45de70d1..f69ac0a7 100644 --- a/course-2021-1/exercises/02-adventure-time/AdventureTime/AdventureTime/Time.cs +++ b/course-2021-1/exercises/02-adventure-time/AdventureTime/AdventureTime/Time.cs @@ -14,7 +14,7 @@ internal static class Time /// public static DateTime WhatTimeIsIt() { - throw new NotImplementedException(); + return DateTime.Now; } /// @@ -22,7 +22,7 @@ public static DateTime WhatTimeIsIt() /// public static DateTime WhatTimeIsItInUtc() { - throw new NotImplementedException(); + return DateTime.UtcNow; } /// @@ -36,7 +36,7 @@ public static DateTime SpecifyKind(DateTime dt, DateTimeKind kind) /* Подсказка: поищи в статических методах DateTime. */ - throw new NotImplementedException(); + return DateTime.SpecifyKind(dt, kind); } /// @@ -51,7 +51,7 @@ Обязательно поиграйся и посмотри на измене Ну и на будущее запомни этот прекрасный строковый формат представления времени - он твой бро! Название запоминать не нужно, просто помни, что для передачи значения в виде строки, выбирать лучше инвариантные относительно сериализации/десериализации форматы. */ - throw new NotImplementedException(); + return dt.ToString("o"); } /// @@ -65,7 +65,7 @@ public static DateTime ParseFromRoundTripFormat(string dtStr) Поиграйся и проверь, что round-trip действительно round-trip, т.е. туда-обратно равно оригиналу (для туда воспользуйся предыдущим методом). Проверь для всех значений DateTime.Kind. */ - throw new NotImplementedException(); + return DateTime.Parse(dtStr, null, System.Globalization.DateTimeStyles.RoundtripKind); } /// @@ -77,7 +77,7 @@ public static DateTime ToUtc(DateTime dt) Eсли воспользуешься нужным методом, то напоминаю, что результат его работы зависит от dt.Kind. В случае dt.Kind == Unspecified предполагается, что время локальное, т.е. результат работы в случае Local и Unspecified совпадают. Такие дела */ - throw new NotImplementedException(); + return dt.ToUniversalTime(); } /// @@ -88,7 +88,7 @@ public static DateTime ToUtc(DateTime dt) public static DateTime AddTenSeconds(DateTime dt) { // здесь воспользуйся методами самого объекта и заодно посмотри какие еще похожие есть - throw new NotImplementedException(); + return dt.AddSeconds(10.0); } /// @@ -101,8 +101,13 @@ public static DateTime AddTenSecondsV2(DateTime dt) /* Ну а здесь воспользуйся сложением с TimeSpan. Обрати внимание, что помимо конструктора, у класса есть набор полезных статических методов-фабрик. Обрати внимание, что у TimeSpan нет статических методов FromMonth, FromYear. Как думаешь, почему? + + * + * Видимо, потому что годы и месяцы имеют разную длительность. + * + */ - throw new NotImplementedException(); + return dt.Add(TimeSpan.FromSeconds(10.0)); } /// @@ -117,8 +122,16 @@ public static int GetHoursBetween(DateTime dt1, DateTime dt2) 1) Подумай, в чем разница между Hours и TotalHours 2) Проверь, учитывается ли Kind объектов при арифметических операциях. 3) Подумай, почему возвращаемое значение может отличаться от действительности. + + * + * 1) `Hours` возвращает число часов в записи времени (например, 1530 минут - это 1 сутки 1 час 30 минут, то есть 1), + * а `TotalHours` возвращает полное время в часах как `double` (например, 150 минут - это 2.5 часа). + * 2) Да (т. е. считается правильная разница, по UTC) + * 3) Из-за ограниченной точности DateTime и вообще чисел с плавающей точкой - например, `(dt.AddMinutes(59.999999) - dt).TotalHours = 1` + * + */ - throw new NotImplementedException(); + return (int)(dt1 - dt2).TotalHours; } /// @@ -127,7 +140,14 @@ public static int GetHoursBetween(DateTime dt1, DateTime dt2) public static int GetTotalMinutesInThreeMonths() { // ну тут все просто и очевидно, если сделал остальные и подумал над вопросами в комментах. - throw new NotImplementedException(); + + /* + * + * Не очевидно - в каких именно трёх месяцах? + * Сделал для 91 дня (т. е. примерно четверть года) + * + */ + return (int)TimeSpan.FromDays(90).TotalMinutes; } #region Adventure time saga @@ -147,7 +167,9 @@ public static int GetAdventureTimeDurationInMinutes_ver0_Dumb() Держи, заготовочку для копипасты: - 2010, 3, 28, 2, 15, 0 */ - throw new NotImplementedException(); + var from = new DateTimeOffset(2010, 3, 28, 2, 15, 0, new TimeSpan(+3, 0, 0)); + var to = new DateTimeOffset(2010, 3, 28, 2, 15, 0, new TimeSpan(+0, 0, 0)); + return (int)(to - from).TotalMinutes; } /// @@ -165,7 +187,9 @@ public static int GetGenderSwappedAdventureTimeDurationInMinutes_ver0_Dumb() - 2010, 3, 28, 3, 15, 0 - 2010, 3, 28, 1, 15, 0 */ - throw new NotImplementedException(); + var from = new DateTimeOffset(2010, 3, 28, 3, 15, 0, new TimeSpan(+3, 0, 0)); + var to = new DateTimeOffset(2010, 3, 28, 1, 15, 0, new TimeSpan(+0, 0, 0)); + return (int)(to - from).TotalMinutes; } /// @@ -180,7 +204,9 @@ Внимательный читатель мог усомниться в дан На самом деле смещения таковы: Лондон +1 (BST - British Summer Time), Москва +4 (MSD - Moscow Daylight Time). Давай теперь учтем правильное смещение. Я понимаю, что это очевидно, что результат не изменится, но тебе же не сложно скопипастить и просто поменять смещения? */ - throw new NotImplementedException(); + var from = new DateTimeOffset(2010, 3, 28, 2, 15, 0, new TimeSpan(+4, 0, 0)); + var to = new DateTimeOffset(2010, 3, 28, 2, 15, 0, new TimeSpan(+1, 0, 0)); + return (int)(to - from).TotalMinutes; } // GetGenderSwappedAdventureTimeDurationInMinutes_ver1_FeelsSmarter опустим, там то же самое @@ -205,7 +231,15 @@ ниже ты найдешь готовый метод GetZonedTime. Прост const string moscowZoneId = "Russian Standard Time"; const string londonZoneId = "GMT Standard Time"; - throw new NotImplementedException(); + /* + * + * Не уточнено время отправления/прибытия (видимо, предполагается 2:15) + * + */ + + var from = Time.GetZonedTime(new DateTime(2010, 3, 28, 2, 15, 0), moscowZoneId); + var to = Time.GetZonedTime(new DateTime(2010, 3, 28, 2, 15, 0), londonZoneId); + return (int)(to - from).TotalMinutes; } /// @@ -218,6 +252,16 @@ public static int GetGenderSwappedAdventureTimeDurationInMinutes_ver2_FeelsLikeR */ const string moscowZoneId = "Russian Standard Time"; const string londonZoneId = "GMT Standard Time"; + + /* + * + * Не уточнено время отправления/прибытия (видимо, предполагается 3:15 и 1:15, как во втором задании) + * + */ + + var from = Time.GetZonedTime(new DateTime(2010, 3, 28, 3, 15, 0), moscowZoneId); + var to = Time.GetZonedTime(new DateTime(2010, 3, 28, 1, 15, 0), londonZoneId); + return (int)(to - from).TotalMinutes; throw new NotImplementedException(); } @@ -277,7 +321,7 @@ private static ZonedDateTime GetZonedTime(LocalDateTime localTime, string timeZo /// True - если родились в один день, иначе - false. internal static bool AreEqualBirthdays(DateTime person1Birthday, DateTime person2Birthday) { - throw new NotImplementedException(); + return person1Birthday.ToString("dd.M").Equals(person2Birthday.ToString("dd.M")); } } } From 28c353370621ddae5e21a2ba8e676c5343fb8623 Mon Sep 17 00:00:00 2001 From: Jeremy Date: Wed, 19 May 2021 01:49:54 +0300 Subject: [PATCH 3/4] TASK 3 - All parts of Task 1: Boring Vector done --- .../BoringVector.Tests.csproj | 23 +++++ .../BoringVector.Tests/VectorTest.cs | 89 ++++++++++++++++++ .../BoringVector/BoringVector.sln | 12 ++- .../BoringVector/BoringVector/Program.cs | 2 + .../BoringVector/BoringVector/Vector.cs | 91 ++++++++++++------- .../BoringVector/VectorExtensions.cs | 78 ++++++++++++++-- 6 files changed, 252 insertions(+), 43 deletions(-) create mode 100644 course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector.Tests/BoringVector.Tests.csproj create mode 100644 course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector.Tests/VectorTest.cs 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..65ec83af --- /dev/null +++ b/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector.Tests/BoringVector.Tests.csproj @@ -0,0 +1,23 @@ + + + + netcoreapp2.0 + + false + + BoringVector.Tests + + BoringVector.Tests + + + + + + + + + + + + + diff --git a/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector.Tests/VectorTest.cs b/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector.Tests/VectorTest.cs new file mode 100644 index 00000000..9cccb06b --- /dev/null +++ b/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector.Tests/VectorTest.cs @@ -0,0 +1,89 @@ +/* + Атрибуты [Fact] и [Theory] означают, что данный метод является тестовым, т.е. TestRunner должен его запускать. + Совсем обывательски - разница в том, что метод с [Theory] дает возможность тестовому методу принимать аргументы и быть запущенным с разными входными данными. + Посмотри на два первых тестовых метода. Первый при тестовом прогоне будет запущен один раз, а второй три - каждый раз с разным набором входных данных. +*/ + +using System; +using Xunit; + +namespace BoringVector.Tests +{ + public class VectorTest + { + [Theory] + [InlineData(3, -4, 25)] + [InlineData(12, 5, 169)] + [InlineData(-0.5, -0.5, 0.5)] + [InlineData(-1.2, 0.0, 1.44)] + [InlineData(0, 0, 0)] + public void Test_SquareLength(double x, double y, double val) + { + Assert.Equal(val, new BoringVector.Vector(x, y).SquareLength()); + } + + [Theory] + [InlineData(1, 1, 1, 1, 2, 2)] + [InlineData(0, -1, -1000, 1001, -1000, 1000)] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.11, -0.5, 0.89, -99.5, 1, -100)] + public void Test_Add(double x1, double y1, double x2, double y2, double x3, double y3) + { + Assert.Equal(x3, (new BoringVector.Vector(x1, y1).Add(new BoringVector.Vector(x2, y2))).X); + Assert.Equal(y3, (new BoringVector.Vector(x1, y1).Add(new BoringVector.Vector(x2, y2))).Y); + } + + [Theory] + [InlineData(1, 1, 1, 1, 2, 2)] + [InlineData(0, -1, -1000, 1001, -1000, 1000)] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.11, -0.5, 0.89, -99.5, 1, -100)] + public void Test_Plus(double x1, double y1, double x2, double y2, double x3, double y3) + { + Assert.Equal(x3, (new BoringVector.Vector(x1, y1) + new BoringVector.Vector(x2, y2)).X); + Assert.Equal(y3, (new BoringVector.Vector(x1, y1) + new BoringVector.Vector(x2, y2)).Y); + } + + [Theory] + [InlineData(1, 1, 2, 2, 2)] + [InlineData(0, -10, -100, 0, 1000)] + [InlineData(5, 0.81, 0, 0, 0)] + [InlineData(0.1, -0.5, 0.5, 0.05, -0.25)] + public void Test_Scale(double x1, double y1, double k, double x3, double y3) + { + Assert.Equal(x3, (new BoringVector.Vector(x1, y1).Scale(k)).X); + Assert.Equal(y3, (new BoringVector.Vector(x1, y1).Scale(k)).Y); + } + + [Theory] + [InlineData(1, 1, 2, 2, 2)] + [InlineData(0, -10, -100, 0, 1000)] + [InlineData(5, 0.81, 0, 0, 0)] + [InlineData(0.1, -0.5, 0.5, 0.05, -0.25)] + public void Test_Mult(double x1, double y1, double k, double x3, double y3) + { + Assert.Equal(x3, (new BoringVector.Vector(x1, y1) * k).X); + Assert.Equal(y3, (new BoringVector.Vector(x1, y1) * k).Y); + } + + [Theory] + [InlineData(1, 1, 2, 2, 4)] + [InlineData(10, -10, 0, -100, 1000)] + [InlineData(0.1, 0.81, 1.9, 1, 1)] + [InlineData(0.1, -0.5, 0.5, 0.1, 0)] + public void Test_DotProduct(double x1, double y1, double x2, double y2, double d) + { + Assert.Equal(d, new BoringVector.Vector(x1, y1).DotProduct(new BoringVector.Vector(x2, y2))); + } + + [Theory] + [InlineData(1, 0, 2, 2, 2)] + [InlineData(1, 0, 0, 1, 1)] + [InlineData(1, 0, 0, -1, -1)] + [InlineData(0.5, 0.5, 2, 0, -1)] + public void Test_CrossProduct(double x1, double y1, double x2, double y2, double d) + { + Assert.Equal(d, new BoringVector.Vector(x1, y1).CrossProduct(new BoringVector.Vector(x2, y2))); + } + } +} 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..d4f4ec7a 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.31229.75 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", "{2E2E7D93-85FE-4B5D-BF16-E280A8AB5852}" 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 + {2E2E7D93-85FE-4B5D-BF16-E280A8AB5852}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2E2E7D93-85FE-4B5D-BF16-E280A8AB5852}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2E2E7D93-85FE-4B5D-BF16-E280A8AB5852}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2E2E7D93-85FE-4B5D-BF16-E280A8AB5852}.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/Program.cs b/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector/Program.cs index f5873162..8edc9e5e 100644 --- a/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector/Program.cs +++ b/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector/Program.cs @@ -1,5 +1,7 @@ using System; +using System.Runtime.CompilerServices; +[assembly: InternalsVisibleTo("BoringVector.Tests")] namespace BoringVector { internal class Program 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..194ecfdd 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 @@ -4,71 +4,96 @@ namespace BoringVector { #region 1. Структура Vector - /* - Реализуй структуру Vector - см. комментарии внутри нее. - */ - + /// + /// Simple 2D vector struct. + /// internal struct Vector { /* Vector задается парой вещественных координат X и Y. */ + /// X coordinate + public readonly double X; + /// Y coordinate + public readonly double Y; + public Vector(double _X, double _Y) { X = _X; Y = _Y; } - /* - На месте заглушек добавь реализацию базовых методов вектора: - - квадрат длины - - сумма векторов - - умножение на коэффициент - - скалярное произведение - - векторное произведение (= площадь параллелограмма) - */ - + /// + /// Get the square of the vector's length. + /// + /// Squared length public double SquareLength() { - throw new NotImplementedException(); + return X*X + Y*Y; } + + /// + /// Add another vector. + /// + /// Vector to add + /// The resulting vector public Vector Add(Vector v) { - throw new NotImplementedException(); + return new Vector(X + v.X, Y + v.Y); } + + /// + /// Scale vector by a number. + /// + /// Number to multiply the vector by + /// The resulting vector public Vector Scale(double k) { - throw new NotImplementedException(); + return new Vector(X * k, Y * k); } + + /// + /// Get the dot product of this vector and another. + /// + /// Vector to get the dot product for + /// The resulting dot product public double DotProduct(Vector v) { - throw new NotImplementedException(); + return X*v.X + Y*v.Y; } + + /// + /// Get the cross product of this vector and another + /// (just the magnitude of the cross product vector, since we're in 2D space). + /// + /// Vector to get the cross product for + /// The resulting cross product (as a scalar) public double CrossProduct(Vector v) { - throw new NotImplementedException(); + return X*v.Y - Y*v.X; } - /* - Переопредели ниже метод ToString - пусть выводит (X; Y) - */ + /// + /// Get coords in a string as (X; Y). + /// + /// String of coords + public override string ToString() + { + return $"({X}; {Y})"; + } #region operators - /* - Реализуй также следущие операторы (Vector v, u и double k): - - v + u, v - u - - k * v, v * k, v / k - - +v, -v - */ + public static Vector operator +(Vector v, Vector u) => new Vector(v.X + u.X, v.Y + u.Y); + public static Vector operator -(Vector v, Vector u) => new Vector(v.X - u.X, v.Y - u.Y); + + public static Vector operator *(Vector v, double k) => new Vector(v.X * k, v.Y * k); + public static Vector operator /(Vector v, double k) => new Vector(v.X / k, v.Y / k); + + public static Vector operator +(Vector v) => new Vector(v.X, v.Y); + public static Vector operator -(Vector v) => new Vector(-v.X, -v.Y); #endregion } #endregion - /* - Время отправиться в VectorExtensions.cs за новой порцией квестов, герой! - Как закончишь, возвращайся за щедрым вознаграждением! - */ - - #region 3. Комментарии /* 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..89d6c136 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,10 +1,74 @@ namespace BoringVector { - /* - Здесь тебе нужно написать класс с методами-расширениями структуры Vector: - - IsZero: проверяет, является ли вектор нулевым, т.е. его координаты близки к нулю (в эпсилон окрестности). За эпсилон здесь и далее берем 1e-6. - - Normalize: нормализует вектор - - GetAngleBetween: возвращает угол между двумя векторами в радианах. Примечание: нулевой вектор сонаправлен любому другому. - - GetRelation: возвращает значение перечесления VectorRelation(General, Parallel, Orthogonal) - отношение между двумя векторами("общий случай", параллельны, перпендикулярны). Перечисление задавать тоже тебе) - */ + /// + /// Some useful methods for . + /// + internal class VectorExtensions + { + + /// + /// A two-vector reltion. + /// + public enum VectorRelation + { + /// Just two vectors + General, + /// Parallel (i. e. scaled or duplicate) vectors + Parallel, + /// Perpendicular vactors + Orthogonal + } + + /// + /// Whether a vector is exactly zero. + /// + /// Is a vector equal to (0; 0)? + public bool IsZero(Vector v) + { + return v.X == 0 && v.Y == 0; + } + + /// + /// Normalizes the length of a vector to 1.0. + /// + /// Scaled vector + public Vector Normalize(Vector v) + { + return v / System.Math.Sqrt(v.SquareLength()); + } + + /// + /// Get the angle between two vectors in radians. + /// + /// The angle in radians from [0; 2π) + public double GetAngleBetween(Vector v, Vector u) + { + var angle = System.Math.Atan2(u.Y, u.X) - System.Math.Atan2(v.Y, v.X); + if (angle < 0) + { + angle += 2 * System.Math.PI; + } + return angle; + } + + /// + /// Get the relation between two vectors - either orthogonal, parallel (or scaled/same) or something else. + /// + /// A relation + public VectorRelation GetRelation(Vector v, Vector u) + { + if (v.CrossProduct(u) == 0) + { + return VectorRelation.Parallel; + } + else if (v.DotProduct(u) == 0) + { + return VectorRelation.Orthogonal; + } + else + { + return VectorRelation.General; + } + } + } } From a9b1569c4a2efc7142d823f42c3881252a1afab5 Mon Sep 17 00:00:00 2001 From: Jeremy Date: Thu, 20 May 2021 13:04:13 +0300 Subject: [PATCH 4/4] TASK 4 - Task 4 - Rick's merciless encryptor done. --- .../AdventureTime/AdventureTime/Time.cs | 2 +- .../RicksMercilessEncryptorTests.cs | 81 +++++++++++++++++++ .../WubbaLubbaDubDub.Tests.csproj | 8 ++ .../WubbaLubbaDubDub/Program.cs | 13 +++ .../RicksMercilessEncryptor.cs | 76 ++++++++++++++--- 5 files changed, 169 insertions(+), 11 deletions(-) create mode 100644 course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub/Program.cs diff --git a/course-2021-1/exercises/02-adventure-time/AdventureTime/AdventureTime/Time.cs b/course-2021-1/exercises/02-adventure-time/AdventureTime/AdventureTime/Time.cs index f69ac0a7..d64e8b67 100644 --- a/course-2021-1/exercises/02-adventure-time/AdventureTime/AdventureTime/Time.cs +++ b/course-2021-1/exercises/02-adventure-time/AdventureTime/AdventureTime/Time.cs @@ -147,7 +147,7 @@ public static int GetTotalMinutesInThreeMonths() * Сделал для 91 дня (т. е. примерно четверть года) * */ - return (int)TimeSpan.FromDays(90).TotalMinutes; + return (int)TimeSpan.FromDays(91).TotalMinutes; } #region Adventure time saga diff --git a/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub.Tests/RicksMercilessEncryptorTests.cs b/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub.Tests/RicksMercilessEncryptorTests.cs index 434f02aa..a4b18dd3 100644 --- a/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub.Tests/RicksMercilessEncryptorTests.cs +++ b/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub.Tests/RicksMercilessEncryptorTests.cs @@ -6,5 +6,86 @@ namespace WubbaLubbaDubDub.Tests public class RicksMercilessEncryptorTests { + [Theory] + [InlineData("", "")] + [InlineData(" ", "")] + [InlineData("abcdefg", "abc")] + [InlineData("\neven\n", "\nev")] + public void Test_GetLeftHalf(string a, string b) + { + Assert.Equal(b, a.GetLeftHalf()); + } + + [Theory] + [InlineData("", "")] + [InlineData(" ", " ")] + [InlineData("abcdefg", "defg")] + [InlineData("\neven\n", "en\n")] + public void Test_GetRightHalf(string a, string b) + { + Assert.Equal(b, a.GetRightHalf()); + } + + [Theory] + [InlineData("abcdefg a again", 'a', '_', "_bcdefg _ _g_in")] + [InlineData("No change", ' ', ' ', "No change")] + [InlineData("", 'a', 'b', "")] + [InlineData("\na\nb\nc\n", '\n', ' ', " a b c ")] + public void Test_Replace(string a, char o, char n, string b) + { + Assert.Equal(b, a.Replace(o, n)); + } + + [Theory] + [InlineData("", "")] + [InlineData(" ", "\\u0020")] + [InlineData("abcdefg", "\\u0061\\u0062\\u0063\\u0064\\u0065\\u0066\\u0067")] + [InlineData("1\n_?\t'!%&\\", "\\u0031\\u000a\\u005f\\u003f\\u0009\\u0027\\u0021\\u0025\\u0026\\u005c")] + public void Test_CharsToCodes(string a, string b) + { + Assert.Equal(b, a.CharsToCodes()); + } + + [Theory] + [InlineData("", new string[] {""})] + [InlineData("\n\n\n", new string[] {"", "", "", ""})] + [InlineData("\n \n\n", new string[] {"", " ", "", ""})] + [InlineData("Never gonna give you up\nNever gonna let you down\nNever gonna run around and desert you", + new string[] {"Never gonna give you up", "Never gonna let you down", "Never gonna run around and desert you"})] + public void Test_SplitToLines(string a, string[] b) + { + Assert.Equal(b, a.SplitToLines()); + } + + [Theory] + [InlineData("", new string[] {})] + [InlineData(" a b cdef ", new string[] {"a", "b", "cdef"})] + [InlineData("a test string", new string[] {"a", "test", "string"})] + [InlineData(" ", new string[] {})] + public void Test_SplitToWords(string a, string[] b) + { + Assert.Equal(b, a.SplitToWords()); + } + + [Theory] + [InlineData("", "")] + [InlineData(" ", " ")] + [InlineData("abc", "cba")] + [InlineData("Big\nFloppa", "appolF\ngiB")] + public void Test_GetReversed(string a, string b) + { + Assert.Equal(b, a.GetReversed()); + } + + [Theory] + [InlineData("", "")] + [InlineData(" ", " ")] + [InlineData("abc", "ABC")] + [InlineData("Big\nFloppa", "bIG\nfLOPPA")] + public void Test_InverseCase(string a, string b) + { + Assert.Equal(b, a.InverseCase()); + } + } } diff --git a/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub.Tests/WubbaLubbaDubDub.Tests.csproj b/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub.Tests/WubbaLubbaDubDub.Tests.csproj index aa2f23f5..140b433f 100644 --- a/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub.Tests/WubbaLubbaDubDub.Tests.csproj +++ b/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub.Tests/WubbaLubbaDubDub.Tests.csproj @@ -4,6 +4,10 @@ netcoreapp2.0 false + + WubbaLubbaDubDub.Tests + + WubbaLubbaDubDub.Tests @@ -12,4 +16,8 @@ + + + + diff --git a/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub/Program.cs b/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub/Program.cs new file mode 100644 index 00000000..dc5cf273 --- /dev/null +++ b/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub/Program.cs @@ -0,0 +1,13 @@ +using System; +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("WubbaLubbaDubDub.Tests")] +namespace WubbaLubbaDubDub +{ + internal class Program + { + private static void Main() + { + } + } +} diff --git a/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub/RicksMercilessEncryptor.cs b/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub/RicksMercilessEncryptor.cs index 1063065b..ab078ebc 100644 --- a/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub/RicksMercilessEncryptor.cs +++ b/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub/RicksMercilessEncryptor.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; - +using System.Text.RegularExpressions; namespace WubbaLubbaDubDub { public static class RicksMercilessEncryptor @@ -12,7 +12,7 @@ public static class RicksMercilessEncryptor public static string[] SplitToLines(this string text) { // У строки есть специальный метод. Давай здесь без регулярок - throw new NotImplementedException(); + return text.SplitToLines(); } /// @@ -21,7 +21,13 @@ public static string[] SplitToLines(this string text) public static string[] SplitToWords(this string line) { // А вот здесь поиграйся с регулярками. - throw new NotImplementedException(); + /* + * + * Хорошо, но разве не проще String.Split(' ')? + * + */ + //return Regex.Split(line, @"\s+"); + return line.Split(' ', StringSplitOptions.RemoveEmptyEntries); } /// @@ -31,7 +37,7 @@ public static string[] SplitToWords(this string line) public static string GetLeftHalf(this string s) { // у строки есть метод получения подстроки - throw new NotImplementedException(); + return s.Substring(0, s.Length / 2); } /// @@ -40,7 +46,7 @@ public static string GetLeftHalf(this string s) /// public static string GetRightHalf(this string s) { - throw new NotImplementedException(); + return s.Substring(s.Length / 2); } /// @@ -49,7 +55,7 @@ public static string GetRightHalf(this string s) public static string Replace(this string s, string old, string @new) { // и такой метод у строки, очевидно, тоже есть - throw new NotImplementedException(); + return s.Replace(old, @new); } /// @@ -65,7 +71,21 @@ а затем использовать её для посимвольного п FYI: локальную функцию можно объявлять даже после строки с return. То же самое можно сделать и для всех оставшихся методов. */ - throw new NotImplementedException(); + + /// + /// Возвращает кодовую точку одного символа. + /// + int GetCode(char c) + { + return Convert.ToByte(c); + } + + string codes = ""; + foreach (char c in s) + { + codes += $"\\u{GetCode(c).ToString("x4")}"; + } + return codes; } /// @@ -77,7 +97,9 @@ public static string GetReversed(this string s) Собрать строку из последовательности строк можно несколькими способами. Один из низ - статический метод Concat. Но ты можешь выбрать любой. */ - throw new NotImplementedException(); + char[] array = s.ToCharArray(); + Array.Reverse(array); + return String.Concat(array); } /// @@ -90,7 +112,16 @@ Здесь тебе помогут статические методы типа На минуту задержись здесь и посмотри, какие еще есть статические методы у char. Например, он содержит методы-предикаты для определения категории Юникода символа, что очень удобно. */ - throw new NotImplementedException(); + char[] array = s.ToCharArray(); + for (int i = 0; i < s.Length; i++) + { + char c = array[i]; + if(Char.IsUpper(c)) + array[i] = Char.ToLower(c); + else + array[i] = Char.ToUpper(c); + } + return String.Concat(array); } /// @@ -117,7 +148,32 @@ public static IImmutableList GetUsedObjects(this string text) Задача на поиграться с регулярками - вся сложность в том, чтобы аккуратно игнорировать комментарии. Экспериментировать онлайн можно, например, здесь: http://regexstorm.net/tester и https://regexr.com/ */ - throw new NotImplementedException(); + + /* + * + * Непонятно условие - как именно записаны байты идентификатора в тексте? + * Здесь предполагается что идентификаторы записаны в тексте так: + * + * ``` + * Never gonna 31b9:6f8c you up + * Never gonna let you a3ba:188a + * Never gonna run around and 14hh:00b5 you + * Never gonna make you 58f4:7cdc + * // Never gonna say 4dd9:00a0 + * Never gonna tell 6aac:2f9c and 31b9:6f8c you + * ``` + * + */ + + HashSet objectIDs = new HashSet(); + MatchCollection matches = Regex.Matches(text, @"(?