diff --git a/course-2021-1/exercises/02-adventure-time/AdventureTime/AdventureTime/Program.cs b/course-2021-1/exercises/02-adventure-time/AdventureTime/AdventureTime/Program.cs index af4efcae..79114770 100644 --- a/course-2021-1/exercises/02-adventure-time/AdventureTime/AdventureTime/Program.cs +++ b/course-2021-1/exercises/02-adventure-time/AdventureTime/AdventureTime/Program.cs @@ -1,9 +1,39 @@ -namespace AdventureTime +using System; + +namespace AdventureTime { internal class Program { private static void Main() { + DateTime dt = Time.WhatTimeIsIt(); + DateTime udt = Time.WhatTimeIsItInUtc(); + + Console.WriteLine(dt); + Console.WriteLine(udt); + + // all the same + Console.WriteLine(Time.SpecifyKind(dt, DateTimeKind.Utc)); + Console.WriteLine(Time.SpecifyKind(dt, DateTimeKind.Local)); + Console.WriteLine(Time.SpecifyKind(dt, DateTimeKind.Unspecified)); + + var roundtrip = Time.ToRoundTripFormatString(dt); + Console.WriteLine(roundtrip); + Console.WriteLine(Time.ParseFromRoundTripFormat(roundtrip)); + + Console.WriteLine(Time.AddTenSeconds(dt)); + Console.WriteLine(Time.AddTenSecondsV2(dt)); + + Console.WriteLine(Time.GetHoursBetween(udt, dt)); + Console.WriteLine(Time.GetTotalMinutesInThreeMonths()); + + Console.WriteLine(Time.GetAdventureTimeDurationInMinutes_ver0_Dumb()); + Console.WriteLine(Time.GetGenderSwappedAdventureTimeDurationInMinutes_ver0_Dumb()); + Console.WriteLine(Time.GetAdventureTimeDurationInMinutes_ver1_FeelsSmarter()); + Console.WriteLine(Time.GetAdventureTimeDurationInMinutes_ver3_NodaTime()); + + Console.WriteLine(Time.AreEqualBirthdays(dt, udt)); + Console.WriteLine(Time.AreEqualBirthdays(dt, udt.AddDays(1))); } } } 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..c9c18a3a 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,22 +36,28 @@ public static DateTime SpecifyKind(DateTime dt, DateTimeKind kind) /* Подсказка: поищи в статических методах DateTime. */ - throw new NotImplementedException(); + return DateTime.SpecifyKind(dt, kind); } /// - /// Конвертирует объект в эквивалентное ему строковое представление времени в формате ISO 8601 (aka round-trip format). + /// Конвертирует объект в эквивалентное ему + /// строковое представление времени в формате ISO 8601 (aka round-trip + /// format). /// /// Объект для конвертации в строку. /// Строковое представление времени в формате ISO 8601. public static string ToRoundTripFormatString(DateTime dt) { /* - Обязательно поиграйся и посмотри на изменение результата в зависимости от dt.Kind (для этого тебе поможет метод выше). - Ну и на будущее запомни этот прекрасный строковый формат представления времени - он твой бро! - Название запоминать не нужно, просто помни, что для передачи значения в виде строки, выбирать лучше инвариантные относительно сериализации/десериализации форматы. + Обязательно поиграйся и посмотри на изменение результата в + зависимости от dt.Kind (для этого тебе поможет метод выше). Ну + и на будущее запомни этот прекрасный строковый формат + представления времени - он твой бро! Название запоминать не + нужно, просто помни, что для передачи значения в виде строки, + выбирать лучше инвариантные относительно + сериализации/десериализации форматы. */ - throw new NotImplementedException(); + return dt.ToString("s", System.Globalization.CultureInfo.InvariantCulture); } /// @@ -62,10 +68,11 @@ public static string ToRoundTripFormatString(DateTime dt) public static DateTime ParseFromRoundTripFormat(string dtStr) { /* - Поиграйся и проверь, что round-trip действительно round-trip, т.е. туда-обратно равно оригиналу (для туда воспользуйся предыдущим методом). - Проверь для всех значений DateTime.Kind. + Поиграйся и проверь, что round-trip действительно round-trip, + т.е. туда-обратно равно оригиналу (для туда воспользуйся + предыдущим методом). Проверь для всех значений DateTime.Kind. */ - throw new NotImplementedException(); + return DateTime.Parse(dtStr, null, System.Globalization.DateTimeStyles.RoundtripKind); } /// @@ -74,10 +81,12 @@ public static DateTime ParseFromRoundTripFormat(string dtStr) public static DateTime ToUtc(DateTime dt) { /* - Eсли воспользуешься нужным методом, то напоминаю, что результат его работы зависит от dt.Kind. - В случае dt.Kind == Unspecified предполагается, что время локальное, т.е. результат работы в случае Local и Unspecified совпадают. Такие дела + Eсли воспользуешься нужным методом, то напоминаю, что результат + его работы зависит от dt.Kind. В случае dt.Kind == Unspecified + предполагается, что время локальное, т.е. результат работы в + случае Local и Unspecified совпадают. Такие дела */ - throw new NotImplementedException(); + return dt.ToUniversalTime(); } /// @@ -88,7 +97,7 @@ public static DateTime ToUtc(DateTime dt) public static DateTime AddTenSeconds(DateTime dt) { // здесь воспользуйся методами самого объекта и заодно посмотри какие еще похожие есть - throw new NotImplementedException(); + return dt.AddSeconds(10); } /// @@ -99,10 +108,13 @@ public static DateTime AddTenSeconds(DateTime dt) public static DateTime AddTenSecondsV2(DateTime dt) { /* - Ну а здесь воспользуйся сложением с TimeSpan. Обрати внимание, что помимо конструктора, у класса есть набор полезных статических методов-фабрик. - Обрати внимание, что у TimeSpan нет статических методов FromMonth, FromYear. Как думаешь, почему? + Ну а здесь воспользуйся сложением с TimeSpan. Обрати внимание, + что помимо конструктора, у класса есть набор полезных + статических методов-фабрик. Обрати внимание, что у TimeSpan нет + статических методов FromMonth, FromYear. Как думаешь, почему? */ - throw new NotImplementedException(); + var ten_sec = new TimeSpan(0, 0, 10); + return dt.Add(ten_sec); } /// @@ -118,7 +130,7 @@ public static int GetHoursBetween(DateTime dt1, DateTime dt2) 2) Проверь, учитывается ли Kind объектов при арифметических операциях. 3) Подумай, почему возвращаемое значение может отличаться от действительности. */ - throw new NotImplementedException(); + return Convert.ToInt32(Math.Abs((dt2 - dt1).TotalHours)); } /// @@ -127,7 +139,8 @@ public static int GetHoursBetween(DateTime dt1, DateTime dt2) public static int GetTotalMinutesInThreeMonths() { // ну тут все просто и очевидно, если сделал остальные и подумал над вопросами в комментах. - throw new NotImplementedException(); + var three_month = new TimeSpan(3*30, 0, 0, 0); + return Convert.ToInt32(three_month.TotalSeconds); } #region Adventure time saga @@ -136,27 +149,41 @@ public static int GetTotalMinutesInThreeMonths() /// Возвращает количество минут, проведенных в пути из Москвы в Лондон. /// /// - /// Финн и Джейк, плотно поужинав, решили, что спать для слабаков и настало время приключений, поэтому быстро собрали вещи, уложили спать БиМО и отправились из воображаемой Москвы в воображаемый Лондон верхом на леди Ливнероге. - /// Сколько минут они провели в пути, если Москву они покинули 28.03.2010 в 02:15 по местному времени, а в Лондон прибыли в 28.03.2010 в 02:15 по местному? + /// Финн и Джейк, плотно поужинав, решили, что спать для слабаков и + /// настало время приключений, поэтому быстро собрали вещи, уложили + /// спать БиМО и отправились из воображаемой Москвы в воображаемый + /// Лондон верхом на леди Ливнероге. Сколько минут они провели в пути, + /// если Москву они покинули 28.03.2010 в 02:15 по местному времени, а в + /// Лондон прибыли в 28.03.2010 в 02:15 по местному? /// public static int GetAdventureTimeDurationInMinutes_ver0_Dumb() { /* - Как ты понимаешь, время выбрано не просто так, но для начала давай прикинемся совсем наивными. - Лондон находится в часовом поясе +0 (GMT), а Москва в +3 (MSK). Воспользуйся DateTimeOffset, чтобы задать правильное время, и посчитай разницу в минутах. Посмотри на результат. - Держи, заготовочку для копипасты: + Как ты понимаешь, время выбрано не просто так, но для начала + давай прикинемся совсем наивными. Лондон находится в часовом + поясе +0 (GMT), а Москва в +3 (MSK). Воспользуйся + DateTimeOffset, чтобы задать правильное время, и посчитай + разницу в минутах. Посмотри на результат. Держи, заготовочку + для копипасты: - 2010, 3, 28, 2, 15, 0 */ - throw new NotImplementedException(); + var london_t = new DateTimeOffset(2010, 3, 28, 2, 15, 0, TimeSpan.FromHours(0)); + var moscow_t = new DateTimeOffset(2010, 3, 28, 2, 15, 0, TimeSpan.FromHours(3)); + + return Convert.ToInt32(Math.Abs((moscow_t - london_t).TotalMinutes)); } /// /// Возвращает количество минут, проведенных в пути из Москвы в Лондон. /// /// - /// Фионна и Кейк, поужинав заварными пироженками от принца Жвачки, решили, что они еще слишком молоды чтобы спать по ночам и сейчас самое время для приключений! Дамы собрали вещи, уложили спать БиМО и отправились из - /// другой воображаемой Москвы в другой воображаемый Лондон верхом на лорде Монохроме. - /// Сколько минут они провели в путешествии, если Москву они покинули 28.03.2010 в 03:15 по местному времени, а в Лондон прибыли в 28.03.2010 в 01:15 по местному? + /// Фионна и Кейк, поужинав заварными пироженками от принца Жвачки, + /// решили, что они еще слишком молоды чтобы спать по ночам и сейчас + /// самое время для приключений! Дамы собрали вещи, уложили спать БиМО и + /// отправились из другой воображаемой Москвы в другой воображаемый + /// Лондон верхом на лорде Монохроме. Сколько минут они провели в + /// путешествии, если Москву они покинули 28.03.2010 в 03:15 по местному + /// времени, а в Лондон прибыли в 28.03.2010 в 01:15 по местному? /// public static int GetGenderSwappedAdventureTimeDurationInMinutes_ver0_Dumb() { @@ -165,7 +192,10 @@ public static int GetGenderSwappedAdventureTimeDurationInMinutes_ver0_Dumb() - 2010, 3, 28, 3, 15, 0 - 2010, 3, 28, 1, 15, 0 */ - throw new NotImplementedException(); + var london_t = new DateTimeOffset(2010, 3, 28, 1, 15, 0, TimeSpan.FromHours(0)); + var moscow_t = new DateTimeOffset(2010, 3, 28, 3, 15, 0, TimeSpan.FromHours(3)); + + return Convert.ToInt32(Math.Abs((moscow_t - london_t).TotalMinutes)); } /// @@ -174,13 +204,22 @@ public static int GetGenderSwappedAdventureTimeDurationInMinutes_ver0_Dumb() public static int GetAdventureTimeDurationInMinutes_ver1_FeelsSmarter() { /* - Глава вторая, в которой оказывается, что в некоторых странах принята такая штука как летнее время (не совсем то, про которое поет Лана Дель Рей). - - Внимательный читатель мог усомниться в данных мной часовых поясах и их смещении относительно UTC и был бы прав. - На самом деле смещения таковы: Лондон +1 (BST - British Summer Time), Москва +4 (MSD - Moscow Daylight Time). - Давай теперь учтем правильное смещение. Я понимаю, что это очевидно, что результат не изменится, но тебе же не сложно скопипастить и просто поменять смещения? + Глава вторая, в которой оказывается, что в некоторых странах + принята такая штука как летнее время (не совсем то, про которое + поет Лана Дель Рей). + + Внимательный читатель мог усомниться в данных мной часовых + поясах и их смещении относительно UTC и был бы прав. На самом + деле смещения таковы: Лондон +1 (BST - British Summer Time), + Москва +4 (MSD - Moscow Daylight Time). Давай теперь учтем + правильное смещение. Я понимаю, что это очевидно, что результат + не изменится, но тебе же не сложно скопипастить и просто + поменять смещения? */ - throw new NotImplementedException(); + var london_t = new DateTimeOffset(2010, 3, 28, 1, 15, 0, TimeSpan.FromHours(1)); + var moscow_t = new DateTimeOffset(2010, 3, 28, 3, 15, 0, TimeSpan.FromHours(4)); + + return Convert.ToInt32(Math.Abs((moscow_t - london_t).TotalMinutes)); } // GetGenderSwappedAdventureTimeDurationInMinutes_ver1_FeelsSmarter опустим, там то же самое @@ -191,21 +230,39 @@ public static int GetAdventureTimeDurationInMinutes_ver1_FeelsSmarter() public static int GetAdventureTimeDurationInMinutes_ver2_FeelsLikeRocketScience() { /* - Глава третья и последняя, в которой внезапно оказывается, что Финн и Фионна находятся в суперпозиции и существуют в виде гендерно нейтрального сверхчеловека, который и путешествовал из Москвы в Лондон. - - Дело в том, что перевод на летнее время в 2010м году в Москве произошел в 02:00 (стрелки часов перевели на час вперед), а в Лондоне - в 01:00. - Таким образом в Москве не было 02:15 - однако можно, например, считать, что этому времени соответствует 03:15. Ну а в Лондоне 01:15 это на самом деле 02:15. - Только как это обработать в рамках класса DateTimeOffset? Да, для конкретного примера мы могли бы сами ручками "перевести стрелки" и поставить правильное время, но что делать в общем случае? - Тут придется воспользоваться знанием о часовых поясах. Их есть у .Net. - - Дабы ты не мучился[-ась], роя в недрах msdn и stackoverflow в поисках ответа (в конце концов, когда тебе это в жизни действительно понадобится), - ниже ты найдешь готовый метод GetZonedTime. Просто посмотри на него (можешь даже посмотреть методы и свойства типа TimeZoneInfo, если интересно) и воспользуйся им для вычисления правильного времени - "отбытия" и "прибытия" наших героев. Затем посчитай длительность путешествия. Также даны правильные идентификаторы зон. + Глава третья и последняя, в которой внезапно оказывается, что + Финн и Фионна находятся в суперпозиции и существуют в виде + гендерно нейтрального сверхчеловека, который и путешествовал из + Москвы в Лондон. + + Дело в том, что перевод на летнее время в 2010м году в Москве + произошел в 02:00 (стрелки часов перевели на час вперед), а в + Лондоне - в 01:00. Таким образом в Москве не было 02:15 - + однако можно, например, считать, что этому времени соответствует + 03:15. Ну а в Лондоне 01:15 это на самом деле 02:15. Только как + это обработать в рамках класса DateTimeOffset? Да, для + конкретного примера мы могли бы сами ручками "перевести стрелки" + и поставить правильное время, но что делать в общем случае? Тут + придется воспользоваться знанием о часовых поясах. Их есть у + .Net. + + Дабы ты не мучился[-ась], роя в недрах msdn и stackoverflow в + поисках ответа (в конце концов, когда тебе это в жизни + действительно понадобится), ниже ты найдешь готовый метод + GetZonedTime. Просто посмотри на него (можешь даже посмотреть + методы и свойства типа TimeZoneInfo, если интересно) и + воспользуйся им для вычисления правильного времени "отбытия" и + "прибытия" наших героев. Затем посчитай длительность + путешествия. Также даны правильные идентификаторы зон. */ const string moscowZoneId = "Russian Standard Time"; const string londonZoneId = "GMT Standard Time"; - throw new NotImplementedException(); + var london_t = new DateTimeOffset(2010, 3, 28, 1, 15, 0, TimeSpan.FromHours(1)); + var moscow_t = new DateTimeOffset(2010, 3, 28, 3, 15, 0, TimeSpan.FromHours(4)); + + return Math.Abs(Convert.ToInt32(GetZonedTime(moscow_t.LocalDateTime, moscowZoneId) - + GetZonedTime(london_t.LocalDateTime, londonZoneId))); } /// @@ -214,11 +271,18 @@ public static int GetAdventureTimeDurationInMinutes_ver2_FeelsLikeRocketScience( public static int GetGenderSwappedAdventureTimeDurationInMinutes_ver2_FeelsLikeRocketScience() { /* - Реши по аналогии с предыдущим методом и проверь, что оба метода действительно возвращают одно и то же время (и что оно правильное). + Реши по аналогии с предыдущим методом и проверь, что оба метода + действительно возвращают одно и то же время (и что оно + правильное). */ const string moscowZoneId = "Russian Standard Time"; const string londonZoneId = "GMT Standard Time"; - throw new NotImplementedException(); + + var london_t = new DateTimeOffset(2010, 3, 28, 1, 15, 0, TimeSpan.FromHours(0)); + var moscow_t = new DateTimeOffset(2010, 3, 28, 3, 15, 0, TimeSpan.FromHours(3)); + + return Convert.ToInt32(GetZonedTime(moscow_t.LocalDateTime, moscowZoneId) - + GetZonedTime(london_t.LocalDateTime, londonZoneId)); } private static DateTimeOffset GetZonedTime(DateTime localTime, string timeZoneId) @@ -232,7 +296,9 @@ private static DateTimeOffset GetZonedTime(DateTime localTime, string timeZoneId Console.WriteLine($"{localTime}: invalid = {isInvalid}; daylight = {isDaylightSaving}; ambigous = {isAmbiguous}"); - // несмотря на то, что DateTimeOffset хранит локальное время + смещение, в действительности здесь мы вычисляем правильное абсолютное значение (время UTC) + // несмотря на то, что DateTimeOffset хранит локальное время + + // смещение, в действительности здесь мы вычисляем правильное + // абсолютное значение (время UTC) return new DateTimeOffset(localTime, timeZone.GetUtcOffset(localTime)); } @@ -247,12 +313,18 @@ public static int GetAdventureTimeDurationInMinutes_ver3_NodaTime() const string londonTimeZoneId = "Europe/London"; const string moscowTimeZoneId = "Europe/Moscow"; - // Тип LocalDateTime не хранит информации о том, где "наблюдается" это время, но явно говорит, что данное время нужно трактовать как есть и никаких неявных преобразований не делать. - // Более того, его апи не позволяет тебе сделать что-то неявно или трактовать это время как-то иначе. Например, его невозможно превратить в абсолютное время UTC (в Noda Time ему отвечает тип Instant) + // Тип LocalDateTime не хранит информации о том, где "наблюдается" + // это время, но явно говорит, что данное время нужно трактовать как + // есть и никаких неявных преобразований не делать. Более того, его + // апи не позволяет тебе сделать что-то неявно или трактовать это + // время как-то иначе. Например, его невозможно превратить в + // абсолютное время UTC (в Noda Time ему отвечает тип Instant) var from = new LocalDateTime(2010, 3, 28, 2, 15, 0); var to = new LocalDateTime(2010, 3, 28, 2, 15, 0); - //Тип ZonedDateTime - это ровным счетом LocalDateTime + DateTimeZone (локальное время + часовой пояс). Вот из него абсолютное время уже можно получить (информации достаточно). + // Тип ZonedDateTime - это ровным счетом LocalDateTime + DateTimeZone + // (локальное время + часовой пояс). Вот из него абсолютное время уже + // можно получить (информации достаточно). var fromMoscowZoned = GetZonedTime(from, moscowTimeZoneId); var toLondonZoned = GetZonedTime(to, londonTimeZoneId); return (int) (toLondonZoned - fromMoscowZoned).TotalMinutes; @@ -260,10 +332,15 @@ public static int GetAdventureTimeDurationInMinutes_ver3_NodaTime() private static ZonedDateTime GetZonedTime(LocalDateTime localTime, string timeZoneId) { - // здесь используется не windows-specific словарь идентификаторов, а более "принятый" сообществом + // здесь используется не windows-specific словарь идентификаторов, а + // более "принятый" сообществом var timeZone = TzdbDateTimeZoneSource.Default.ForId(timeZoneId); - // обрати внимание, есть два метода, превращающих локальное время + часовой пояс в ZonedDateTime: InZoneLeniently и InZoneStrictly. Первый не ругается на сомнительное локальное время, второй - бросает исключение. Для наглядности конкретно этого примера я использовал "снисходительный" вариант. + // обрати внимание, есть два метода, превращающих локальное время + + // часовой пояс в ZonedDateTime: InZoneLeniently и InZoneStrictly. + // Первый не ругается на сомнительное локальное время, второй - + // бросает исключение. Для наглядности конкретно этого примера я + // использовал "снисходительный" вариант. return localTime.InZoneLeniently(timeZone); } @@ -277,7 +354,9 @@ private static ZonedDateTime GetZonedTime(LocalDateTime localTime, string timeZo /// True - если родились в один день, иначе - false. internal static bool AreEqualBirthdays(DateTime person1Birthday, DateTime person2Birthday) { - throw new NotImplementedException(); + return person1Birthday.Year == person2Birthday.Year && + person1Birthday.Month == person2Birthday.Month && + person1Birthday.Day == person2Birthday.Day; } } } 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..122b68e1 --- /dev/null +++ b/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector.Tests/BoringVector.Tests.csproj @@ -0,0 +1,25 @@ + + + + net5.0 + + false + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + 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..f495c69f --- /dev/null +++ b/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector.Tests/VectorTest.cs @@ -0,0 +1,50 @@ +using System; +using Xunit; + +namespace BoringVector.Tests +{ + public class VectorTest + { + [Fact] + public void Test_SquareLength() + { + Vector v = new Vector(3, 4); + Assert.Equal(25, v.SquareLength()); + } + [Theory] + [InlineData(1, 5)] + [InlineData(0, 0)] + [InlineData(-1, 1)] + public void Test_Add(double x, double y) + { + Vector v = new Vector(3, 4); + Vector u = new Vector(x, y); + v.Add(u); + Assert.Equal(new Vector(3+x, 4+y).ToString(), v.ToString()); + } + [Theory] + [InlineData(5)] + [InlineData(0)] + [InlineData(-2)] + public void Test_Scale(double scale) + { + Vector v = new Vector(3, 4); + v.Scale(scale); + Assert.Equal(new Vector(3*scale, 4*scale).ToString(), v.ToString()); + } + [Fact] + public void Test_DotProduct() + { + Vector v = new Vector(3, 4); + Vector u = new Vector(1, -1); + Assert.Equal(-1, v.DotProduct(u)); + } + [Fact] + public void Test_CrossProduct() + { + Vector v = new Vector(3, 4); + Vector u = new Vector(4, -3); + Assert.Equal(-25, v.CrossProduct(u)); + } + } +} diff --git a/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector/BoringVector.csproj b/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector/BoringVector.csproj index ce1697ae..680291a4 100644 --- a/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector/BoringVector.csproj +++ b/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector/BoringVector.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp2.0 + netcoreapp5.0 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..5c94dfd1 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,4 +1,7 @@ using System; +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("BoringVector.Tests")] namespace BoringVector { 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..dd2c1745 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,5 +1,6 @@ using System; + namespace BoringVector { #region 1. Структура Vector @@ -8,12 +9,21 @@ namespace BoringVector Реализуй структуру Vector - см. комментарии внутри нее. */ - internal struct Vector + /// + /// Класс, реализующий двумерный вектор. + /// + internal class Vector { /* Vector задается парой вещественных координат X и Y. */ - + protected double x; + protected double y; + public Vector(double x, double y) + { + this.x = x; + this.y = y; + } /* На месте заглушек добавь реализацию базовых методов вектора: @@ -24,30 +34,54 @@ internal struct Vector - векторное произведение (= площадь параллелограмма) */ + /// + /// Квадрат длины вектора. + /// public double SquareLength() { - throw new NotImplementedException(); + return x*x + y*y; } + /// + /// Сложение векторов (in-place). + /// + /// Вектор, который будет прибавлен к текущему. public Vector Add(Vector v) { - throw new NotImplementedException(); + x += v.x; + y += v.y; + return this; } + /// + /// Умножение на скаляр (in-place). + /// + /// Коэффициент. public Vector Scale(double k) { - throw new NotImplementedException(); + x *= k; + y *= k; + return this; } + /// + /// Скалярное произведение векторов. + /// + /// Вектор, с которым берётся скалярное произведение. public double DotProduct(Vector v) { - throw new NotImplementedException(); + return x*v.x + y*v.y; } + /// + /// Векторное произведение векторов. + /// + /// Вектор, с которым берётся векторное произведение. public double CrossProduct(Vector v) { - throw new NotImplementedException(); + return x*v.y - y*v.x; } /* Переопредели ниже метод ToString - пусть выводит (X; Y) */ + public override string ToString() => String.Format("({0}; {1})", x, y); #region operators @@ -57,6 +91,10 @@ public double CrossProduct(Vector v) - k * v, v * k, v / k - +v, -v */ + public static Vector operator+(Vector v) => v; + public static Vector operator-(Vector v) => new Vector(-v.x, -v.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, Vector u) => new Vector(v.x - u.x, v.y - u.y); #endregion } @@ -72,30 +110,43 @@ public double CrossProduct(Vector v) #region 3. Комментарии /* - Прости, я соврал. К сожалению, пока ты делал(-а) вторую часть, человек, который понимал, о чем идет речь в первой части, - успел съездить в путешествие под названием "во все тяжкие" и теперь проходит курс реабилитации. А те, кто был хотя бы примерно в теме, - внезапно лишились рассудка. - Тут еще из будущего сообщили, что тебе дали задачу поинтереснее, и ты наотрез отказался(-ась) сотрудничать в передаче знаний. - Ну а вместо тебя на эту задачу взяли пушистого котика, который отказывается разбираться в коде и уж тем более его писать - говорит у него лапки. - - В такой ситуации единственно возможное решение задачи - оставить после себя комментарии. Такие, чтобы даже котику было понятно! - В общем, впереди неприятная для многих часть - необходимо добавить комментарии ко всем введенным типам, методам и свойствам :) - - + Прости, я соврал. К сожалению, пока ты делал(-а) вторую часть, человек, + который понимал, о чем идет речь в первой части, успел съездить в + путешествие под названием "во все тяжкие" и теперь проходит курс + реабилитации. А те, кто был хотя бы примерно в теме, внезапно лишились + рассудка. Тут еще из будущего сообщили, что тебе дали задачу + поинтереснее, и ты наотрез отказался(-ась) сотрудничать в передаче + знаний. Ну а вместо тебя на эту задачу взяли пушистого котика, который + отказывается разбираться в коде и уж тем более его писать - говорит у + него лапки. + + В такой ситуации единственно возможное решение задачи - оставить после + себя комментарии. Такие, чтобы даже котику было понятно! В общем, + впереди неприятная для многих часть - необходимо добавить комментарии ко + всем введенным типам, методам и свойствам :) + + _Хозяйке на заметку_ - - Для многих это действительно довольно неприятная и скучнейшая часть - писать комментарии к коду. Проблема в том, - что это еще и не так просто как кажется на первый взгляд. Очень желательно выдерживать единый стиль, писать по существу, - писать не "для текущего разобравшегося в проблеме и предметной области себя", а для "того парня", "себя через год". Ну или пушистого котика. - - Есть и хорошее в этом деле. Комментирование кода очень похоже на написание автотестов - оно позволяет взглянуть - на задачу и ее решение немного с другой стороны. Например, если слова не вяжутся, и не получается написать простое и короткое - описание к методу или типу - это хороший сигнал, что он "с душком", и его стоит переделать/отрефакторить. - Я лично чаще пишу комментарии ближе к концу работы над задачей. Это позволяет мне еще раз просмотреть весь написанный код под - слегка иным углом обзора и самому сделать первичный code review. - - - Ты мог(-ла) заметить, что в предыдущих заданиях для комментариев я использовал немного необычный синтаксис: + + Для многих это действительно довольно неприятная и скучнейшая часть - + писать комментарии к коду. Проблема в том, что это еще и не так просто + как кажется на первый взгляд. Очень желательно выдерживать единый стиль, + писать по существу, писать не "для текущего разобравшегося в проблеме и + предметной области себя", а для "того парня", "себя через год". Ну или + пушистого котика. + + Есть и хорошее в этом деле. Комментирование кода очень похоже на + написание автотестов - оно позволяет взглянуть на задачу и ее решение + немного с другой стороны. Например, если слова не вяжутся, и не + получается написать простое и короткое описание к методу или типу - это + хороший сигнал, что он "с душком", и его стоит переделать/отрефакторить. + Я лично чаще пишу комментарии ближе к концу работы над задачей. Это + позволяет мне еще раз просмотреть весь написанный код под слегка иным + углом обзора и самому сделать первичный code review. + + + Ты мог(-ла) заметить, что в предыдущих заданиях для комментариев я + использовал немного необычный синтаксис: /// /// Возвращает объект с заданными временем и значением . @@ -104,33 +155,52 @@ public double CrossProduct(Vector v) /// Значение , задающий соответствующее свойство возвращаемого объекта. /// Объект с заданными временем и значением . - Такой блок является комментарием, т.к. каждая строка начинается с //, но имеет свою внутреннюю структуру и синтаксис. - Это так называемые Xml documentation comments. Их поддерживает сам компилятор. Они позволяют писать чуть более умные и продвинутые комментарии к сущностям, - а потом, например, автоматически генерировать по ним красивую документацию. - Правилом хорошего тона считается писать комментарии к методам, классам и другим сущностям, используя данный синтаксис - так ты и комментируешь их, и документируешь. - Внутри методов он не поддерживается, поэтому там только обычные (// или /*). - - Ниже приведены примеры простейших комментариев. Если наведете мышкой на название метода DoNothing, увидишь, - что студия отображает комментарий в подписи (в других IDE из коробки без плагинов это вряд ли будет работать). - Если навести на аргумент метода DoNothing - something, увидишь комментарий к нему. - Наведи теперь на NotImplementedException() - комментарий во всплывашке сделан с помощью такого же синтаксиса. - Код .Net Framework задокументирован именно таким синтаксисом. - - Чтобы создать такой комментарий, не нужно писать разметку целиком самому. Если ввести ///, студия сама создаст нужные блоки. + Такой блок является комментарием, т.к. каждая строка начинается с //, но + имеет свою внутреннюю структуру и синтаксис. Это так называемые Xml + documentation comments. Их поддерживает сам компилятор. Они позволяют + писать чуть более умные и продвинутые комментарии к сущностям, а потом, + например, автоматически генерировать по ним красивую документацию. + Правилом хорошего тона считается писать комментарии к методам, классам и + другим сущностям, используя данный синтаксис - так ты и комментируешь + их, и документируешь. Внутри методов он не поддерживается, поэтому там + только обычные (// или /*). + + Ниже приведены примеры простейших комментариев. Если наведете мышкой на + название метода DoNothing, увидишь, что студия отображает комментарий в + подписи (в других IDE из коробки без плагинов это вряд ли будет + работать). Если навести на аргумент метода DoNothing - something, + увидишь комментарий к нему. Наведи теперь на NotImplementedException() + - комментарий во всплывашке сделан с помощью такого же синтаксиса. Код + .Net Framework задокументирован именно таким синтаксисом. + + Чтобы создать такой комментарий, не нужно писать разметку целиком + самому. Если ввести ///, студия сама создаст нужные блоки. Плюсы Xml documentation comments: - - блок комментариев имеет четкую предзаданную структуру, что дает возможность воспользоваться различными инструментариями - автогенерации документации (и создавать, например, документацию вроде MSDN). - В последней лабе мы, надеюсь, научимся генерировать для web api страничку с документацией к нашему апи и увидим, что генератор в том числе - может для каждого метода апи создавать формочку для его проверки и ручного тестирования. - - IDE может показывать ее в чуть более удобном виде, нежели если бы ты писал(-а) их обычным способом. - Например, показывать во всплывающей подсказке только самое необходимое короткое описание, а длинное с пояснениями и примерами кода не показывать. - - все названия типов, методов и свойств можно задавать в виде ссылки, например, , и это - будет строгая, проверяемая компилятором, ссылка. Ты, думаю, помнишь, что компилятор как сервис в частности предоставляет разные возможности рефакторинга, - например, переименование. Так вот, если воспользоваться им и переименовать метод DotProduct у структуры Vector, то - переименуется и текст в ссылке. Если же ссылка указывает на невалидную сущность, то студия явно даст понять: "Cannot resolve symbol 'blah-blah-blah'". - Я лично не проверял, но по идее можно даже сделать так, чтобы в таком случае была ошибка компиляции. В генерируемой же документации эти ссылки будут - заменены на реальные ссылки на страницы описания соответствующей сущности, что довольно удобно для навигации по ней. + - блок комментариев имеет четкую предзаданную структуру, что дает + возможность воспользоваться различными инструментариями + автогенерации документации (и создавать, например, документацию + вроде MSDN). В последней лабе мы, надеюсь, научимся генерировать + для web api страничку с документацией к нашему апи и увидим, что + генератор в том числе может для каждого метода апи создавать + формочку для его проверки и ручного тестирования. + - IDE может показывать ее в чуть более удобном виде, нежели если бы + ты писал(-а) их обычным способом. Например, показывать во + всплывающей подсказке только самое необходимое короткое описание, а + длинное с пояснениями и примерами кода не показывать. + - все названия типов, методов и свойств можно задавать в виде + ссылки, например, , и это будет + строгая, проверяемая компилятором, ссылка. Ты, думаю, помнишь, что + компилятор как сервис в частности предоставляет разные возможности + рефакторинга, например, переименование. Так вот, если + воспользоваться им и переименовать метод DotProduct у структуры + Vector, то переименуется и текст в ссылке. Если же ссылка указывает + на невалидную сущность, то студия явно даст понять: "Cannot resolve + symbol 'blah-blah-blah'". Я лично не проверял, но по идее можно + даже сделать так, чтобы в таком случае была ошибка компиляции. В + генерируемой же документации эти ссылки будут заменены на реальные + ссылки на страницы описания соответствующей сущности, что довольно + удобно для навигации по ней. */ @@ -160,28 +230,36 @@ public static void ThrowNotImplementedException() #region 4. Тесты /* - Прости еще раз, но на этом твои мучения еще не кончаются. Проблема в том, что у котика все еще лапки, поэтому очень важно - покрыть тестами хотя бы базовые методы структуры Vector: + Прости еще раз, но на этом твои мучения еще не кончаются. Проблема в + том, что у котика все еще лапки, поэтому очень важно покрыть тестами + хотя бы базовые методы структуры Vector: SquareLength Add Scale DotProduct CrossProduct - Для этого создай в этом же солюшене (если ты не в студии, то можешь и не в солюшене) проект BoringVector.Tests, - который будет содержать класс с набором тестов. Используй Xunit (в принципе можешь воспользоваться и другим фреймворком для тестирования). + Для этого создай в этом же солюшене (если ты не в студии, то можешь и не + в солюшене) проект BoringVector.Tests, который будет содержать класс с + набором тестов. Используй Xunit (в принципе можешь воспользоваться и + другим фреймворком для тестирования). - Особо не заморачивайся с тем, чтобы оттестировать все возможные специальные случаи - в данном задании важно, чтобы - ты просто разобрался(-ась), как писать автотесты и как их запускать. Это задание НЕ на то, как писать хорошие тесты. + Особо не заморачивайся с тем, чтобы оттестировать все возможные + специальные случаи - в данном задании важно, чтобы ты просто + разобрался(-ась), как писать автотесты и как их запускать. Это задание + НЕ на то, как писать хорошие тесты. - Примечание: структура Vector описана как internal структура, поэтому по умолчанию сборке BoringVector.Tests она не видна. - Чтобы она была видна, существует специальная директива компилятору: + Примечание: структура Vector описана как internal структура, поэтому по + умолчанию сборке BoringVector.Tests она не видна. Чтобы она была видна, + существует специальная директива компилятору: [assembly: InternalsVisibleTo("XXX")] , где XXX - название проекта, которому ты хочешь сделать видимыми свои internal'ы. - Можешь посмотреть, в задании [01-primitive-types] эта директива есть в файле Program.cs проекта Numbers. + Можешь посмотреть, в задании [01-primitive-types] эта директива есть в + файле Program.cs проекта Numbers. - Итак, создай проект с тестами и добейся того, чтобы базовые методы структуры Vector их проходили. + Итак, создай проект с тестами и добейся того, чтобы базовые методы + структуры Vector их проходили. */ #endregion 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..07b4e7c7 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,58 @@ -namespace BoringVector +using System; + +namespace BoringVector { + enum VectorRelation + { + General, + Parallel, + Orthogonal + } /* Здесь тебе нужно написать класс с методами-расширениями структуры Vector: - - IsZero: проверяет, является ли вектор нулевым, т.е. его координаты близки к нулю (в эпсилон окрестности). За эпсилон здесь и далее берем 1e-6. + - IsZero: проверяет, является ли вектор нулевым, т.е. его координаты + близки к нулю (в эпсилон окрестности). За эпсилон здесь и далее + берем 1e-6. - Normalize: нормализует вектор - - GetAngleBetween: возвращает угол между двумя векторами в радианах. Примечание: нулевой вектор сонаправлен любому другому. - - GetRelation: возвращает значение перечесления VectorRelation(General, Parallel, Orthogonal) - отношение между двумя векторами("общий случай", параллельны, перпендикулярны). Перечисление задавать тоже тебе) + - GetAngleBetween: возвращает угол между двумя векторами в радианах. + Примечание: нулевой вектор сонаправлен любому другому. + - GetRelation: возвращает значение перечесления + VectorRelation(General, Parallel, Orthogonal) - отношение между + двумя векторами("общий случай", параллельны, перпендикулярны). + Перечисление задавать тоже тебе) */ + internal class ExtendedVector : Vector + { + const double eps = 0.000001; + public ExtendedVector(double x, double y) : base(x, y) {} + public bool IsZero() + { + return Math.Abs(x) < eps && Math.Abs(y) < eps; + } + + public ExtendedVector Normalize() + { + double len = Math.Sqrt(SquareLength()); + x /= len; + y /= len; + return this; + } + + static public double GetAngleBetween(ExtendedVector v, ExtendedVector u) + { + if (v.IsZero() || u.IsZero()) { + return 0; + } + return Math.Acos(v.Normalize().DotProduct(u.Normalize())); + } + static public VectorRelation GetRelation(ExtendedVector v, ExtendedVector u) + { + if (v.CrossProduct(u) == 0) { + return VectorRelation.Parallel; + } else if (v.DotProduct(u) == 0) { + return VectorRelation.Orthogonal; + } + return VectorRelation.General; + } + } } 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..264c222e 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 @@ -5,6 +5,76 @@ namespace WubbaLubbaDubDub.Tests { public class RicksMercilessEncryptorTests { - + [Fact] + private static void Test_SplitToLines() + { + string text = "Hello\nWorld"; + var list = text.SplitToLines(); + Assert.Equal("Hello", list[0]); + Assert.Equal("World", list[1]); + } + [Fact] + private static void Test_SplitToWords() + { + string text = "Hello World"; + var list = text.SplitToWords(); + Assert.Equal("Hello", list[0]); + Assert.Equal("World", list[1]); + } + [Fact] + private static void Test_GetLeftHalf() + { + string text = "Hello World"; + Assert.Equal("Hello", text.GetLeftHalf()); + } + [Fact] + private static void Test_GetRightHalf() + { + string text = "Hello World"; + Assert.Equal(" World", text.GetRightHalf()); + } + [Fact] + private static void Test_GetRightHalf() + { + string text = "Hello World"; + Assert.Equal("He11o World", text.Replace("ll", "11")); + } + [Fact] + private static void Test_CharsToCodes() + { + string text = "He"; + Assert.Equal("\\u0048\\u0065", text.CharsToCodes()); + } + [Fact] + private static void Test_GetReversed() + { + string text = "Hello"; + Assert.Equal("olleH", text.GetReversed()); + } + [Fact] + private static void Test_InverseCase() + { + string text = "Hello"; + Assert.Equal("hELLO", text.InverseCase()); + } + [Fact] + private static void Test_ShiftInc() + { + string text = "Hello"; + Assert.Equal("Ifmmp", text.InverseCase()); + } + [Fact] + private static void Test_GetUsedObjects() + { + string str = + @"// comment + dead:beef + /* + Задача на поиграться с регулярками - вся сложность в том, чтобы аккуратно игнорировать комментарии. + Экспериментировать онлайн можно, например, здесь: http://regexstorm.net/tester и https://regexr.com/ + */"; + + Assert.Equal(3735928559, str.GetUsedObjects()); + } } } 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..e45b0939 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 @@ -1,7 +1,7 @@ - netcoreapp2.0 + netcoreapp5.0 false @@ -12,4 +12,10 @@ + + + + + + diff --git a/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub/Benchmark.cs b/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub/Benchmark.cs new file mode 100644 index 00000000..72251572 --- /dev/null +++ b/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub/Benchmark.cs @@ -0,0 +1,38 @@ +using System; +using System.Text; +using System.Security.Cryptography; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +namespace MyBenchmarks +{ + public class StringAdd + { + private const int N = 1000; + private readonly string data; + + private readonly StringBuilder stringbuilder = new StringBuilder(""); + + public StringAdd() + { + data = new string('*', N); + } + + [Benchmark] + public string Join() => string.Join("", data); + + [Benchmark] + public string BuilderJoin() => stringbuilder.AppendJoin("", data).ToString(); + + [Benchmark] + public string Concatenate() => string.Concat(data); + } + + public class Program + { + public static void Main() + { + var summary = BenchmarkRunner.Run(); + } + } +} diff --git a/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub/BenchmarkDotNet.Artifacts/results/MyBenchmarks.StringAdd-report-github.md b/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub/BenchmarkDotNet.Artifacts/results/MyBenchmarks.StringAdd-report-github.md new file mode 100644 index 00000000..70da1f2b --- /dev/null +++ b/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub/BenchmarkDotNet.Artifacts/results/MyBenchmarks.StringAdd-report-github.md @@ -0,0 +1,15 @@ +``` ini + +BenchmarkDotNet=v0.13.0, OS=ubuntu 20.04 +Intel Core i5-8250U CPU 1.60GHz (Kaby Lake R), 1 CPU, 8 logical and 4 physical cores +.NET SDK=5.0.203 + [Host] : .NET 5.0.6 (5.0.621.22011), X64 RyuJIT + DefaultJob : .NET 5.0.6 (5.0.621.22011), X64 RyuJIT + + +``` +| Method | Mean | Error | StdDev | +|------------ |-----------------:|------------------:|------------------:| +| Join | 26.94 ns | 0.526 ns | 0.439 ns | +| BuilderJoin | 85,051,155.23 ns | 11,071,144.320 ns | 32,643,518.817 ns | +| Concatenate | 15.47 ns | 2.106 ns | 6.209 ns | diff --git a/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub/BenchmarkDotNet.Artifacts/results/MyBenchmarks.StringAdd-report.csv b/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub/BenchmarkDotNet.Artifacts/results/MyBenchmarks.StringAdd-report.csv new file mode 100644 index 00000000..54146a7c --- /dev/null +++ b/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub/BenchmarkDotNet.Artifacts/results/MyBenchmarks.StringAdd-report.csv @@ -0,0 +1,4 @@ +Method,Job,AnalyzeLaunchVariance,EvaluateOverhead,MaxAbsoluteError,MaxRelativeError,MinInvokeCount,MinIterationTime,OutlierMode,Affinity,EnvironmentVariables,Jit,Platform,PowerPlanMode,Runtime,AllowVeryLargeObjects,Concurrent,CpuGroups,Force,HeapAffinitizeMask,HeapCount,NoAffinitize,RetainVm,Server,Arguments,BuildConfiguration,Clock,EngineFactory,NuGetReferences,Toolchain,IsMutator,InvocationCount,IterationCount,IterationTime,LaunchCount,MaxIterationCount,MaxWarmupIterationCount,MemoryRandomization,MinIterationCount,MinWarmupIterationCount,RunStrategy,UnrollFactor,WarmupCount,Mean,Error,StdDev +Join,DefaultJob,False,Default,Default,Default,Default,Default,Default,11111111,Empty,RyuJit,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 5.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,1,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,26.94 ns,0.526 ns,0.439 ns +BuilderJoin,DefaultJob,False,Default,Default,Default,Default,Default,Default,11111111,Empty,RyuJit,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 5.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,1,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,"85,051,155.23 ns","11,071,144.320 ns","32,643,518.817 ns" +Concatenate,DefaultJob,False,Default,Default,Default,Default,Default,Default,11111111,Empty,RyuJit,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 5.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,1,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,15.47 ns,2.106 ns,6.209 ns diff --git a/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub/BenchmarkDotNet.Artifacts/results/MyBenchmarks.StringAdd-report.html b/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub/BenchmarkDotNet.Artifacts/results/MyBenchmarks.StringAdd-report.html new file mode 100644 index 00000000..178d3cf0 --- /dev/null +++ b/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub/BenchmarkDotNet.Artifacts/results/MyBenchmarks.StringAdd-report.html @@ -0,0 +1,32 @@ + + + + +MyBenchmarks.StringAdd-20210527-005536 + + + + +

+BenchmarkDotNet=v0.13.0, OS=ubuntu 20.04
+Intel Core i5-8250U CPU 1.60GHz (Kaby Lake R), 1 CPU, 8 logical and 4 physical cores
+.NET SDK=5.0.203
+  [Host]     : .NET 5.0.6 (5.0.621.22011), X64 RyuJIT
+  DefaultJob : .NET 5.0.6 (5.0.621.22011), X64 RyuJIT
+
+
+ + + + + + + +
Method Mean Error StdDev
Join26.94 ns0.526 ns0.439 ns
BuilderJoin85,051,155.23 ns11,071,144.320 ns32,643,518.817 ns
Concatenate15.47 ns2.106 ns6.209 ns
+ + 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..9d874a13 --- /dev/null +++ b/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub/Program.cs @@ -0,0 +1,11 @@ +using System; +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("WubbaLubbaDubDub.Tests")] + +namespace WubbaLubbaDubDub +{ + class Program + { + } +} 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..4fbb019c 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,6 +1,9 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Text.RegularExpressions; +using System.Linq; + namespace WubbaLubbaDubDub { @@ -11,8 +14,7 @@ public static class RicksMercilessEncryptor ///
public static string[] SplitToLines(this string text) { - // У строки есть специальный метод. Давай здесь без регулярок - throw new NotImplementedException(); + return text.Split('\n'); } /// @@ -20,8 +22,10 @@ public static string[] SplitToLines(this string text) /// public static string[] SplitToWords(this string line) { - // А вот здесь поиграйся с регулярками. - throw new NotImplementedException(); + return Regex.Matches(line, "([A-Za-z]+)") + .OfType() + .Select(m => m.Value) + .ToArray(); } /// @@ -31,7 +35,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 +44,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 +53,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 +69,12 @@ public static string CharsToCodes(this string s) FYI: локальную функцию можно объявлять даже после строки с return. То же самое можно сделать и для всех оставшихся методов. */ - throw new NotImplementedException(); + return string.Concat(s.ToCharArray().Select(c => ToUTF16(c)).ToArray()); + + string ToUTF16(char c) + { + return "\\u" + ((int)c).ToString("X4"); + } } /// @@ -77,7 +86,17 @@ public static string GetReversed(this string s) Собрать строку из последовательности строк можно несколькими способами. Один из низ - статический метод Concat. Но ты можешь выбрать любой. */ - throw new NotImplementedException(); + return string.Concat(Reverse(s)); + + char[] Reverse(string s) + { + char[] rev = new char[s.Length]; + for (int i = 0; i < s.Length; ++i) + { + rev[i] = s[s.Length - 1 - i]; + } + return rev; + } } /// @@ -90,7 +109,18 @@ public static string InverseCase(this string s) На минуту задержись здесь и посмотри, какие еще есть статические методы у char. Например, он содержит методы-предикаты для определения категории Юникода символа, что очень удобно. */ - throw new NotImplementedException(); + + return string.Concat( + s.ToCharArray().Select(c => Inverse(c)).ToArray()); + + char Inverse(char c) + { + if (char.IsLower(c)) + { + return char.ToUpper(c); + } + return char.ToLower(c); + } } /// @@ -99,25 +129,38 @@ public static string InverseCase(this string s) /// public static string ShiftInc(this string s) { - throw new NotImplementedException(); + return string.Concat( + s.ToCharArray().Select(c => (char)(c + 1)).ToArray()); } #region Чуть посложнее /// - /// Возвращает список уникальных идентификаторов объектов, используемых в тексте . - /// Идентификаторы объектов имеют длину 8байт и представлены в тексте в виде ¶X:Y¶, где X - старшие 4 байта, а Y - младшие 4 байта. - /// Текст так же содержит строчные (//) и блоковые (/**/) комментарии, которые нужно игнорировать. - /// Т.е. в комментариях идентификаторы объектов искать не нужно. И, кстати, блоковые комментарии могут быть многострочными. + /// Возвращает список уникальных идентификаторов объектов, используемых + /// в тексте . Идентификаторы объектов имеют длину + /// 8байт и представлены в тексте в виде ¶X:Y¶, где X - старшие 4 байта, + /// а Y - младшие 4 байта. Текст так же содержит + /// строчные (//) и блоковые (/**/) комментарии, которые нужно + /// игнорировать. Т.е. в комментариях идентификаторы объектов искать не + /// нужно. И, кстати, блоковые комментарии могут быть многострочными. /// + public static IImmutableList GetUsedObjects(this string text) + //public static string GetUsedObjects(this string text) { /* Задача на поиграться с регулярками - вся сложность в том, чтобы аккуратно игнорировать комментарии. Экспериментировать онлайн можно, например, здесь: http://regexstorm.net/tester и https://regexr.com/ */ - throw new NotImplementedException(); + // Filter comments: https://stackoverflow.com/a/12089866 + text = Regex.Replace( + text, "(/\\*([^*]|[\r\n]|(\\*+([^*/]|[\r\n])))*\\*+/)|(//.*)", ""); + + return Regex.Matches(text, "([\\da-fA-F]{4}:[\\da-fA-F]{4})") + .OfType() + .Select(m => Convert.ToInt64(m.Value.Replace(":", ""), 16)) + .ToImmutableList(); } #endregion diff --git a/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub/WubbaLubbaDubDub.csproj b/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub/WubbaLubbaDubDub.csproj index 5766db61..8828c1d2 100644 --- a/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub/WubbaLubbaDubDub.csproj +++ b/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub/WubbaLubbaDubDub.csproj @@ -1,7 +1,12 @@ - netcoreapp2.0 + Exe + netcoreapp5.0 + + + +