diff --git a/course-2021-1/exercises/02-adventure-time/AdventureTime/AdventureTime/AdventureTime.csproj b/course-2021-1/exercises/02-adventure-time/AdventureTime/AdventureTime/AdventureTime.csproj index dba2bee8..054b0d0e 100644 --- a/course-2021-1/exercises/02-adventure-time/AdventureTime/AdventureTime/AdventureTime.csproj +++ b/course-2021-1/exercises/02-adventure-time/AdventureTime/AdventureTime/AdventureTime.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp2.0 + net5.0 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..1295ead9 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() { + // Протестируем работу основных методов без Adventure time + System.Console.WriteLine("Base methods"); + System.Console.WriteLine(Time.WhatTimeIsIt()); + System.Console.WriteLine(Time.WhatTimeIsItInUtc()); + System.Console.WriteLine(Time.SpecifyKind(Time.WhatTimeIsItInUtc(), DateTimeKind.Local)); + System.Console.WriteLine(Time.ToRoundTripFormatString(Time.WhatTimeIsIt(), true)); + System.Console.WriteLine(Time.ParseFromRoundTripFormat(Time.ToRoundTripFormatString(Time.WhatTimeIsIt()))); + System.Console.WriteLine(Time.ToUtc(Time.SpecifyKind(Time.WhatTimeIsItInUtc(), DateTimeKind.Local))); + System.Console.WriteLine(Time.AddTenSeconds(Time.WhatTimeIsIt())); + System.Console.WriteLine(Time.AddTenSecondsV2(Time.WhatTimeIsIt())); + System.Console.WriteLine(Time.GetHoursBetween( + new DateTime(2010, 3, 28, 2, 15, 0), + new DateTime(2010, 3, 28, 3, 45, 0)) + ); + System.Console.WriteLine(Time.GetTotalMinutesInThreeMonths()); + System.Console.WriteLine(Time.AreEqualBirthdays( + new DateTime(2010, 3, 28), new DateTime(2000, 4, 1))); + System.Console.WriteLine("==============================================================================="); + + // Протестируем работу методов в Adventure time + System.Console.WriteLine("Adventure time methods"); + System.Console.WriteLine(Time.GetAdventureTimeDurationInMinutes_ver0_Dumb()); + System.Console.WriteLine(Time.GetGenderSwappedAdventureTimeDurationInMinutes_ver0_Dumb()); + System.Console.WriteLine(Time.GetAdventureTimeDurationInMinutes_ver1_FeelsSmarter()); + System.Console.WriteLine(Time.GetAdventureTimeDurationInMinutes_ver2_FeelsLikeRocketScience()); + System.Console.WriteLine(Time.GetGenderSwappedAdventureTimeDurationInMinutes_ver2_FeelsLikeRocketScience()); + System.Console.WriteLine(Time.GetAdventureTimeDurationInMinutes_ver3_NodaTime()); + System.Console.WriteLine("==============================================================================="); } } } 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..7f1e0bb5 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; // Rider хорошо подсказывает.))) } /// @@ -22,7 +22,7 @@ public static DateTime WhatTimeIsIt() /// public static DateTime WhatTimeIsItInUtc() { - throw new NotImplementedException(); + return DateTime.UtcNow; // И тут тоже.) } /// @@ -36,22 +36,39 @@ 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). /// /// Объект для конвертации в строку. + /// Флаг, отвечающий за эксперименты с Kind. /// Строковое представление времени в формате ISO 8601. - public static string ToRoundTripFormatString(DateTime dt) + public static string ToRoundTripFormatString(DateTime dt, bool playWithKind=false) { /* - Обязательно поиграйся и посмотри на изменение результата в зависимости от dt.Kind (для этого тебе поможет метод выше). + Обязательно поиграйся и посмотри на изменение результата в зависимости от dt.Kind (для этого тебе + поможет метод выше). Ну и на будущее запомни этот прекрасный строковый формат представления времени - он твой бро! - Название запоминать не нужно, просто помни, что для передачи значения в виде строки, выбирать лучше инвариантные относительно сериализации/десериализации форматы. + Название запоминать не нужно, просто помни, что для передачи значения в виде строки, выбирать лучше + инвариантные относительно сериализации/десериализации форматы. */ - throw new NotImplementedException(); + + if (playWithKind) + { + System.Console.WriteLine("-----------------\nИграемся с kind в ToRoundTripFormatString:"); + System.Console.WriteLine("Local:"); + System.Console.WriteLine(SpecifyKind(dt, DateTimeKind.Local).ToString("o")); + System.Console.WriteLine("Unspecified:"); + System.Console.WriteLine(SpecifyKind(dt, DateTimeKind.Unspecified).ToString("o")); + System.Console.WriteLine("Utc:"); + System.Console.WriteLine(SpecifyKind(dt, DateTimeKind.Utc).ToString("o")); + System.Console.WriteLine("-----------------"); + } + + return dt.ToString("o"); // По умолчанию должна использоваться культура текущего потока. } /// @@ -62,10 +79,11 @@ public static string ToRoundTripFormatString(DateTime dt) public static DateTime ParseFromRoundTripFormat(string dtStr) { /* - Поиграйся и проверь, что round-trip действительно round-trip, т.е. туда-обратно равно оригиналу (для туда воспользуйся предыдущим методом). + Поиграйся и проверь, что round-trip действительно round-trip, т.е. туда-обратно равно оригиналу + (для туда воспользуйся предыдущим методом). Проверь для всех значений DateTime.Kind. */ - throw new NotImplementedException(); + return DateTime.Parse(dtStr); // По умолчанию используется культура текущего потока, так что всё ок. } /// @@ -75,9 +93,10 @@ public static DateTime ToUtc(DateTime dt) { /* Eсли воспользуешься нужным методом, то напоминаю, что результат его работы зависит от dt.Kind. - В случае dt.Kind == Unspecified предполагается, что время локальное, т.е. результат работы в случае Local и Unspecified совпадают. Такие дела + В случае dt.Kind == Unspecified предполагается, что время локальное, т.е. результат работы в случае + Local и Unspecified совпадают. Такие дела */ - throw new NotImplementedException(); + return dt.ToUniversalTime(); } /// @@ -88,7 +107,7 @@ public static DateTime ToUtc(DateTime dt) public static DateTime AddTenSeconds(DateTime dt) { // здесь воспользуйся методами самого объекта и заодно посмотри какие еще похожие есть - throw new NotImplementedException(); + return dt.AddSeconds(10); } /// @@ -99,10 +118,12 @@ public static DateTime AddTenSeconds(DateTime dt) public static DateTime AddTenSecondsV2(DateTime dt) { /* - Ну а здесь воспользуйся сложением с TimeSpan. Обрати внимание, что помимо конструктора, у класса есть набор полезных статических методов-фабрик. + Ну а здесь воспользуйся сложением с TimeSpan. Обрати внимание, что помимо конструктора, + у класса есть набор полезных статических методов-фабрик. Обрати внимание, что у TimeSpan нет статических методов FromMonth, FromYear. Как думаешь, почему? */ - throw new NotImplementedException(); + return dt + TimeSpan.FromSeconds(10); // он не может быть выражен в терминах лет и месяцев, + // так как они имеют переменное количество дней } /// @@ -118,7 +139,10 @@ public static int GetHoursBetween(DateTime dt1, DateTime dt2) 2) Проверь, учитывается ли Kind объектов при арифметических операциях. 3) Подумай, почему возвращаемое значение может отличаться от действительности. */ - throw new NotImplementedException(); + return (int)dt2.Subtract(dt1).TotalHours; // 1) В доках написано, что Hours возвращает число часов, + // записанное в поле часов внутри DateTime + // 2) В доках написано, что не учитывается + // 3) В доках написано, что если даты в разных часовых поясах, то разница будет ещё включать разницу поясов } /// @@ -127,7 +151,7 @@ public static int GetHoursBetween(DateTime dt1, DateTime dt2) public static int GetTotalMinutesInThreeMonths() { // ну тут все просто и очевидно, если сделал остальные и подумал над вопросами в комментах. - throw new NotImplementedException(); + return (int)TimeSpan.FromDays(90).TotalMinutes; // Нигде не сказано, сколько брать дней в месяцах -_- } #region Adventure time saga @@ -136,27 +160,37 @@ 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 moscowTime = new DateTimeOffset(2010, 3, 28, 2, 15, 0, TimeSpan.FromHours(3)); + var londonTime = new DateTimeOffset(2010, 3, 28, 2, 15, 0, TimeSpan.FromHours(0)); + + return (int)londonTime.Subtract(moscowTime).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 +199,10 @@ public static int GetGenderSwappedAdventureTimeDurationInMinutes_ver0_Dumb() - 2010, 3, 28, 3, 15, 0 - 2010, 3, 28, 1, 15, 0 */ - throw new NotImplementedException(); + var moscowTime = new DateTimeOffset(2010, 3, 28, 3, 15, 0, TimeSpan.FromHours(3)); + var londonTime = new DateTimeOffset(2010, 3, 28, 1, 15, 0, TimeSpan.FromHours(0)); + + return (int)londonTime.Subtract(moscowTime).TotalMinutes; } /// @@ -174,13 +211,18 @@ public static int GetGenderSwappedAdventureTimeDurationInMinutes_ver0_Dumb() public static int GetAdventureTimeDurationInMinutes_ver1_FeelsSmarter() { /* - Глава вторая, в которой оказывается, что в некоторых странах принята такая штука как летнее время (не совсем то, про которое поет Лана Дель Рей). + Глава вторая, в которой оказывается, что в некоторых странах принята такая штука как летнее время + (не совсем то, про которое поет Лана Дель Рей). Внимательный читатель мог усомниться в данных мной часовых поясах и их смещении относительно UTC и был бы прав. На самом деле смещения таковы: Лондон +1 (BST - British Summer Time), Москва +4 (MSD - Moscow Daylight Time). - Давай теперь учтем правильное смещение. Я понимаю, что это очевидно, что результат не изменится, но тебе же не сложно скопипастить и просто поменять смещения? + Давай теперь учтем правильное смещение. Я понимаю, что это очевидно, что результат не изменится, + но тебе же не сложно скопипастить и просто поменять смещения? */ - throw new NotImplementedException(); + var moscowTime = new DateTimeOffset(2010, 3, 28, 2, 15, 0, TimeSpan.FromHours(4)); + var londonTime = new DateTimeOffset(2010, 3, 28, 2, 15, 0, TimeSpan.FromHours(1)); + + return (int)londonTime.Subtract(moscowTime).TotalMinutes; } // GetGenderSwappedAdventureTimeDurationInMinutes_ver1_FeelsSmarter опустим, там то же самое @@ -191,21 +233,37 @@ 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? Да, для конкретного примера мы могли бы сами ручками "перевести стрелки" и поставить правильное время, но что делать в общем случае? + Глава третья и последняя, в которой внезапно оказывается, что Финн и Фионна находятся в суперпозиции + и существуют в виде гендерно нейтрального сверхчеловека, который и путешествовал из Москвы в Лондон. + + Дело в том, что перевод на летнее время в 2010м году в Москве произошел в 02:00 + (стрелки часов перевели на час вперед), а в Лондоне - в 01:00. + Таким образом в Москве не было 02:15 - однако можно, например, считать, что этому времени соответствует + 03:15. Ну а в Лондоне 01:15 это на самом деле 02:15. + Только как это обработать в рамках класса DateTimeOffset? Да, для конкретного примера мы могли бы сами + ручками "перевести стрелки" и поставить правильное время, но что делать в общем случае? Тут придется воспользоваться знанием о часовых поясах. Их есть у .Net. - Дабы ты не мучился[-ась], роя в недрах msdn и stackoverflow в поисках ответа (в конце концов, когда тебе это в жизни действительно понадобится), - ниже ты найдешь готовый метод GetZonedTime. Просто посмотри на него (можешь даже посмотреть методы и свойства типа TimeZoneInfo, если интересно) и воспользуйся им для вычисления правильного времени - "отбытия" и "прибытия" наших героев. Затем посчитай длительность путешествия. Также даны правильные идентификаторы зон. + Дабы ты не мучился[-ась], роя в недрах msdn и stackoverflow в поисках ответа (в конце концов, когда + тебе это в жизни действительно понадобится), + ниже ты найдешь готовый метод GetZonedTime. Просто посмотри на него (можешь даже посмотреть методы и + свойства типа TimeZoneInfo, если интересно) и воспользуйся им для вычисления правильного времени + "отбытия" и "прибытия" наших героев. Затем посчитай длительность путешествия. Также даны правильные + идентификаторы зон. */ - const string moscowZoneId = "Russian Standard Time"; - const string londonZoneId = "GMT Standard Time"; - - throw new NotImplementedException(); + + // НЕ РАБОТАЕТ! + // const string moscowZoneId = "Russian Standard Time"; + // const string londonZoneId = "GMT Standard Time"; + const string londonZoneId = "Europe/London"; + const string moscowZoneId = "Europe/Moscow"; + + var moscowTime = new DateTime(2010, 3, 28, 2, 15, 0); + var londonTime = new DateTime(2010, 3, 28, 2, 15, 0); + var moscowZonedTime = GetZonedTime(moscowTime, moscowZoneId); + var londonZonedTime = GetZonedTime(londonTime, londonZoneId); + + return (int)londonZonedTime.Subtract(moscowZonedTime).TotalMinutes; } /// @@ -214,25 +272,37 @@ 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(); + // const string moscowZoneId = "Russian Standard Time"; + // const string londonZoneId = "GMT Standard Time"; + const string londonZoneId = "Europe/London"; + const string moscowZoneId = "Europe/Moscow"; + + var moscowTime = new DateTime(2010, 3, 28, 3, 15, 0); + var londonTime = new DateTime(2010, 3, 28, 1, 15, 0); + var moscowZonedTime = GetZonedTime(moscowTime, moscowZoneId); + var londonZonedTime = GetZonedTime(londonTime, londonZoneId); + + return (int)londonZonedTime.Subtract(moscowZonedTime).TotalMinutes; } private static DateTimeOffset GetZonedTime(DateTime localTime, string timeZoneId) { - var timeZone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId); + var timeZone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId); // Более продвинутый класс для работы + // с часовыми поясами // и немножечко полезной доп инфы в консоль: var isInvalid = timeZone.IsInvalidTime(localTime); var isDaylightSaving = timeZone.IsDaylightSavingTime(localTime); var isAmbiguous = timeZone.IsAmbiguousTime(localTime); - Console.WriteLine($"{localTime}: invalid = {isInvalid}; daylight = {isDaylightSaving}; ambigous = {isAmbiguous}"); + Console.WriteLine( + $"{localTime}: invalid = {isInvalid}; daylight = {isDaylightSaving}; ambigous = {isAmbiguous}"); - // несмотря на то, что DateTimeOffset хранит локальное время + смещение, в действительности здесь мы вычисляем правильное абсолютное значение (время UTC) + // несмотря на то, что DateTimeOffset хранит локальное время + смещение, в действительности здесь + // мы вычисляем правильное абсолютное значение (время UTC) return new DateTimeOffset(localTime, timeZone.GetUtcOffset(localTime)); } @@ -247,12 +317,15 @@ 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; @@ -263,7 +336,10 @@ private static ZonedDateTime GetZonedTime(LocalDateTime localTime, string timeZo // здесь используется не windows-specific словарь идентификаторов, а более "принятый" сообществом var timeZone = TzdbDateTimeZoneSource.Default.ForId(timeZoneId); - // обрати внимание, есть два метода, превращающих локальное время + часовой пояс в ZonedDateTime: InZoneLeniently и InZoneStrictly. Первый не ругается на сомнительное локальное время, второй - бросает исключение. Для наглядности конкретно этого примера я использовал "снисходительный" вариант. + // обрати внимание, есть два метода, превращающих локальное время + часовой пояс в ZonedDateTime: + // InZoneLeniently и InZoneStrictly. Первый не ругается на сомнительное локальное время, + // второй - бросает исключение. Для наглядности конкретно этого примера я использовал "снисходительный" + // вариант. return localTime.InZoneLeniently(timeZone); } @@ -277,7 +353,7 @@ private static ZonedDateTime GetZonedTime(LocalDateTime localTime, string timeZo /// True - если родились в один день, иначе - false. internal static bool AreEqualBirthdays(DateTime person1Birthday, DateTime person2Birthday) { - throw new NotImplementedException(); + return person1Birthday.Day == person2Birthday.Day; } } } diff --git a/course-2021-1/exercises/03-boring-vector/BoringVector.Tests/BoringVector.Tests.sln b/course-2021-1/exercises/03-boring-vector/BoringVector.Tests/BoringVector.Tests.sln new file mode 100644 index 00000000..02f0a37b --- /dev/null +++ b/course-2021-1/exercises/03-boring-vector/BoringVector.Tests/BoringVector.Tests.sln @@ -0,0 +1,16 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BoringVector.Tests", "BoringVector.Tests\BoringVector.Tests.csproj", "{AD69D7D4-8481-432E-A959-75F8E960CAFA}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {AD69D7D4-8481-432E-A959-75F8E960CAFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AD69D7D4-8481-432E-A959-75F8E960CAFA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AD69D7D4-8481-432E-A959-75F8E960CAFA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AD69D7D4-8481-432E-A959-75F8E960CAFA}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/course-2021-1/exercises/03-boring-vector/BoringVector.Tests/BoringVector.Tests/BoringVector.Tests.csproj b/course-2021-1/exercises/03-boring-vector/BoringVector.Tests/BoringVector.Tests/BoringVector.Tests.csproj new file mode 100644 index 00000000..d90502d8 --- /dev/null +++ b/course-2021-1/exercises/03-boring-vector/BoringVector.Tests/BoringVector.Tests/BoringVector.Tests.csproj @@ -0,0 +1,22 @@ + + + + net5.0 + + false + + BoringVector.Tests + + BoringVector.Tests + + + + + + + + + + + + diff --git a/course-2021-1/exercises/03-boring-vector/BoringVector.Tests/BoringVector.Tests/UnitTest1.cs b/course-2021-1/exercises/03-boring-vector/BoringVector.Tests/BoringVector.Tests/UnitTest1.cs new file mode 100644 index 00000000..05aec049 --- /dev/null +++ b/course-2021-1/exercises/03-boring-vector/BoringVector.Tests/BoringVector.Tests/UnitTest1.cs @@ -0,0 +1,46 @@ +using NUnit.Framework; + +namespace BoringVector.Tests +{ + public class Tests + { + [SetUp] + public void Setup() + { + } + + [Test] + public void SquareLength() + { + var v = new Vector(5, 5); + Assert.AreEqual(v.SquareLength(), 50); + } + [Test] + public void Add() + { + var v = new Vector(5, 5); + var u = new Vector(1, -1); + Assert.AreEqual(v.Add(u), new Vector(6, 4)); + } + [Test] + public void Scale() + { + var v = new Vector(5, 5); + Assert.AreEqual(v.Scale(10), new Vector(50, 50)); + } + [Test] + public void DotProduct() + { + var v = new Vector(5, 5); + var u = new Vector(1, -1); + Assert.AreEqual(v.DotProduct(u), 0); + } + [Test] + public void CrossProduct() + { + var v = new Vector(5, 5); + var u = new Vector(1, -1); + Assert.AreEqual(v.CrossProduct(u), -10); + } + } +} \ No newline at end of file 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..20827042 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 + net5.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..9426559d 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 { @@ -6,7 +9,15 @@ internal class Program { private static void Main() { - Console.WriteLine("Hello World!"); + var v = new ExtendedVector(1, -1); + Console.WriteLine(v.Normilize().ToString()); + + var u1 = new Vector(5, 5); + + Console.WriteLine(u1.SquareLength()); + Console.WriteLine(u1 + u1 * 3); + Console.WriteLine(u1.DotProduct(v)); + Console.WriteLine(u1.CrossProduct(v)); } } } 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..de8892a1 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 @@ -2,18 +2,27 @@ namespace BoringVector { - #region 1. Структура Vector + #region 1. Класс Vector (поменял, чтобы можно было наследоваться). /* Реализуй структуру Vector - см. комментарии внутри нее. */ - internal struct Vector + /// + /// Двумерный радиус-вектор, задающийся парой координат. + /// + public class Vector { /* Vector задается парой вещественных координат X и Y. */ + public readonly double X, Y; + public Vector(double x, double y) + { + X = x; + Y = y; + } /* На месте заглушек добавь реализацию базовых методов вектора: @@ -23,31 +32,64 @@ internal struct Vector - скалярное произведение - векторное произведение (= площадь параллелограмма) */ - + /// + /// Считает квадрат длины вектора. + /// + /// Число типа double --- квадрат длины. public double SquareLength() { - throw new NotImplementedException(); + return X * X + Y * Y; } + /// + /// Добавляет к текущему вектору другой вектор. + /// + /// Второй объект класса . + /// Новый , равный сумме двух заданных. public Vector Add(Vector v) { - throw new NotImplementedException(); + return new Vector(X + v.X, Y + v.Y); } + /// + /// Растягивает (сжимает) вектор в k раз. + /// + /// Число типа . + /// Новый отмасштабированный . public Vector Scale(double k) { - throw new NotImplementedException(); + return new Vector(X * k, Y * k); } + /// + /// Скалярное произведение в R^2. + /// + /// Второй объект класса , с которым считается скалярное + /// произведение. + /// Значение скалярного произведения. public double DotProduct(Vector v) { - throw new NotImplementedException(); + return X * v.X + Y * v.Y; } + /// + /// Векторное произведение в пространстве R^2. + /// + /// Второй объект класса , с которым считается векторное + /// произведение. + /// Значение векторного произведения. public double CrossProduct(Vector v) { - throw new NotImplementedException(); + return X * v.Y - Y * v.X; // судя по инету, оно определяется так в R^2 } /* Переопредели ниже метод ToString - пусть выводит (X; Y) */ + /// + /// Строковое представление вектора. + /// + /// Объект типа , содержащий строковое представление. + public override string ToString() + { + return String.Format("({0};{1})", X, Y); + } #region operators @@ -57,6 +99,40 @@ public double CrossProduct(Vector v) - k * v, v * k, v / k - +v, -v */ + public static Vector operator +(Vector v, Vector u) + { + return v.Add(u); + } + + public static Vector operator -(Vector v, Vector u) + { + return v.Add(-u); + } + + public static Vector operator *(Vector v, double k) + { + return v.Scale(k); + } + + public static Vector operator *(double k, Vector v) + { + return v.Scale(k); + } + + public static Vector operator /(Vector v, double k) + { + return new Vector(v.X / k, v.Y / k); // кажется, что .Scale(1 / k) может некорректно работать + } + + public static Vector operator +(Vector v) + { + return v; + } + + public static Vector operator -(Vector v) + { + return new Vector(-v.X, -v.Y); + } #endregion } @@ -86,7 +162,7 @@ public double CrossProduct(Vector v) Для многих это действительно довольно неприятная и скучнейшая часть - писать комментарии к коду. Проблема в том, что это еще и не так просто как кажется на первый взгляд. Очень желательно выдерживать единый стиль, писать по существу, - писать не "для текущего разобравшегося в проблеме и предметной области себя", а для "того парня", "себя через год". Ну или пушистого котика. + писать не "для текущего разобравшегося в проблеме и предметной области себя", а для "того парня", "себя через год". Ну, или пушистого котика. Есть и хорошее в этом деле. Комментирование кода очень похоже на написание автотестов - оно позволяет взглянуть на задачу и ее решение немного с другой стороны. Например, если слова не вяжутся, и не получается написать простое и короткое @@ -105,10 +181,10 @@ public double CrossProduct(Vector v) /// Объект с заданными временем и значением . Такой блок является комментарием, т.к. каждая строка начинается с //, но имеет свою внутреннюю структуру и синтаксис. - Это так называемые Xml documentation comments. Их поддерживает сам компилятор. Они позволяют писать чуть более умные и продвинутые комментарии к сущностям, - а потом, например, автоматически генерировать по ним красивую документацию. - Правилом хорошего тона считается писать комментарии к методам, классам и другим сущностям, используя данный синтаксис - так ты и комментируешь их, и документируешь. - Внутри методов он не поддерживается, поэтому там только обычные (// или /*). + Это так называемые Xml documentation comments. Их поддерживает сам компилятор. Они позволяют писать чуть более умные + и продвинутые комментарии к сущностям, а потом, например, автоматически генерировать по ним красивую документацию. + Правилом хорошего тона считается писать комментарии к методам, классам и другим сущностям, используя данный синтаксис, + - так ты и комментируешь их, и документируешь. Внутри методов он не поддерживается, поэтому там только обычные (// или /*). Ниже приведены примеры простейших комментариев. Если наведете мышкой на название метода DoNothing, увидишь, что студия отображает комментарий в подписи (в других IDE из коробки без плагинов это вряд ли будет работать). @@ -121,16 +197,19 @@ public double CrossProduct(Vector v) Плюсы Xml documentation comments: - блок комментариев имеет четкую предзаданную структуру, что дает возможность воспользоваться различными инструментариями автогенерации документации (и создавать, например, документацию вроде MSDN). - В последней лабе мы, надеюсь, научимся генерировать для web api страничку с документацией к нашему апи и увидим, что генератор в том числе - может для каждого метода апи создавать формочку для его проверки и ручного тестирования. + В последней лабе мы, надеюсь, научимся генерировать для web api страничку с документацией к нашему апи и увидим, + что генератор в том числе может для каждого метода апи создавать формочку для его проверки и ручного тестирования. - IDE может показывать ее в чуть более удобном виде, нежели если бы ты писал(-а) их обычным способом. - Например, показывать во всплывающей подсказке только самое необходимое короткое описание, а длинное с пояснениями и примерами кода не показывать. + Например, показывать во всплывающей подсказке только самое необходимое короткое описание, а длинное с пояснениями и примерами + кода не показывать. - все названия типов, методов и свойств можно задавать в виде ссылки, например, , и это - будет строгая, проверяемая компилятором, ссылка. Ты, думаю, помнишь, что компилятор как сервис в частности предоставляет разные возможности рефакторинга, - например, переименование. Так вот, если воспользоваться им и переименовать метод DotProduct у структуры Vector, то - переименуется и текст в ссылке. Если же ссылка указывает на невалидную сущность, то студия явно даст понять: "Cannot resolve symbol 'blah-blah-blah'". - Я лично не проверял, но по идее можно даже сделать так, чтобы в таком случае была ошибка компиляции. В генерируемой же документации эти ссылки будут - заменены на реальные ссылки на страницы описания соответствующей сущности, что довольно удобно для навигации по ней. + будет строгая, проверяемая компилятором, ссылка. Ты, думаю, помнишь, что компилятор как сервис в частности + предоставляет разные возможности рефакторинга, например, переименование. Так вот, если воспользоваться им + и переименовать метод DotProduct у структуры Vector, то переименуется и текст в ссылке. Если же ссылка указывает + на невалидную сущность, то студия явно даст понять: "Cannot resolve symbol 'blah-blah-blah'". + Я лично не проверял, но по идее можно даже сделать так, чтобы в таком случае была ошибка компиляции. + В генерируемой же документации эти ссылки будут заменены на реальные ссылки на страницы описания соответствующей сущности, + что довольно удобно для навигации по ней. */ 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..1f17cf9b 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,96 @@ -namespace BoringVector +using System; + +namespace BoringVector { /* Здесь тебе нужно написать класс с методами-расширениями структуры Vector: - - IsZero: проверяет, является ли вектор нулевым, т.е. его координаты близки к нулю (в эпсилон окрестности). За эпсилон здесь и далее берем 1e-6. + - IsZero: проверяет, является ли вектор нулевым, т.е. его координаты близки к нулю (в эпсилон окрестности). + За эпсилон здесь и далее берем 1e-6. - Normalize: нормализует вектор - GetAngleBetween: возвращает угол между двумя векторами в радианах. Примечание: нулевой вектор сонаправлен любому другому. - - GetRelation: возвращает значение перечесления VectorRelation(General, Parallel, Orthogonal) - отношение между двумя векторами("общий случай", параллельны, перпендикулярны). Перечисление задавать тоже тебе) + - GetRelation: возвращает значение перечесления VectorRelation(General, Parallel, Orthogonal) - + отношение между двумя векторами("общий случай", параллельны, перпендикулярны). Перечисление задавать тоже тебе) */ + /// + /// Класс, расширяющий функционал стандартного некоторыми полезными функциями. + /// + internal class ExtendedVector:BoringVector.Vector + { + /// + /// Точность, с которой проверяется равенство нулю координат. + /// + private const double Eps = 1e-6; + /// + /// Возможные взаимоотношения между векторами: параллельны, перпендикулярны, нет определённого отношения. + /// + public enum VectorsRelation + { + Parallel, + Orthogonal, + General, + } + + internal ExtendedVector(double X, double Y) : base(X, Y) {} + + /// + /// Проверяет, является ли вектор нулевым. + /// + /// True, если является, False иначе. + internal bool IsZero() + { + return (Math.Abs(X) < Eps & Math.Abs(Y) < Eps); + } + + /// + /// Нормализует вектор, вычитая среднее и деля на дисперсию. + /// + /// Новый с преобразованными координатами. + internal Vector Normilize() + { + double mean = (X + Y) / 2; + double std = Math.Sqrt((X - mean) * (X - mean) + (Y - mean) * (Y - mean)); + + if (std < Eps) + { + std = Eps; + } + + return new Vector((X - mean) / std, (Y - mean) / std); + } + + /// + /// Считает угол между векторами. + /// + /// Объект класса , угол с которым надо посчитать. + /// Угол между веткорами. + internal double GetAngleBetween(ExtendedVector v) + { + if (IsZero() | v.IsZero()) + { + return 0; + } + + return DotProduct(v) / Math.Sqrt(SquareLength() * v.SquareLength()); + } + + /// + /// Определяет, являются ли векторы перпендикулярными, параллельными, или нет. + /// + /// Объект класса , с которым нужно установить отношение. + /// Одно из трёх значений в . + internal VectorsRelation GetRelation(Vector v) + { + if (Math.Abs(CrossProduct(v)) < Eps) + { + return VectorsRelation.Parallel; + } + + if (Math.Abs(DotProduct(v)) < Eps) + { + return VectorsRelation.Orthogonal; + } + + return VectorsRelation.General; + } + } } diff --git a/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/Benchmark.txt b/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/Benchmark.txt new file mode 100644 index 00000000..de8a3e21 --- /dev/null +++ b/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/Benchmark.txt @@ -0,0 +1,5 @@ +| Method | Mean | Error | StdDev | Median | Max | +|-------------- |----------:|---------:|---------:|----------:|----------:| +| String.Join() | 192.23 us | 3.584 us | 3.681 us | 192.60 us | 197.71 us | +| TestBuilder | 40.26 us | 0.771 us | 1.056 us | 39.94 us | 42.69 us | +| Concat | 69.61 us | 1.076 us | 0.898 us | 69.53 us | 71.65 us | 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..859ff7c8 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 @@ -1,10 +1,79 @@ -using System; using Xunit; +using System.Collections.Generic; +using System.Collections.Immutable; + namespace WubbaLubbaDubDub.Tests { public class RicksMercilessEncryptorTests { - + [Fact] + public void SplitToLinesTest() + { + var expected = new string[] {"for i in range(10):", " print(i)"}; + Assert.Equal(RicksMercilessEncryptor.SplitToLines("for i in range(10):\n print(i)"), expected); + } + + [Fact] + public void SplitToWordsTest() + { + var expected = new string[] {"", "My", "name", "is", "C", ""}; + Assert.Equal(RicksMercilessEncryptor.SplitToWords("! My name is C#!"), expected); + } + + [Fact] + public void GetLeftHalfTest() + { + Assert.Equal(RicksMercilessEncryptor.GetLeftHalf("string"), "str"); + Assert.Equal(RicksMercilessEncryptor.GetLeftHalf("strings"), "str"); + } + + [Fact] + public void GetRightHalfTest() + { + Assert.Equal(RicksMercilessEncryptor.GetRightHalf("string"), "ing"); + Assert.Equal(RicksMercilessEncryptor.GetRightHalf("strings"), "ings"); + } + + [Fact] + public void ReplaceTest() + { + Assert.Equal(RicksMercilessEncryptor.Replace("Svyatoslav", "a", "#"), "Svy#tosl#v"); + } + + [Fact] + public void CharsToCodesTest() + { + Assert.Equal(RicksMercilessEncryptor.CharsToCodes("АБВ"), "\\u0410\\u0411\\u0412"); + } + + [Fact] + public void GetReversedTest() + { + Assert.Equal(RicksMercilessEncryptor.GetReversed("string"), "gnirts"); + } + + [Fact] + public void InverseCaseTest() + { + Assert.Equal(RicksMercilessEncryptor.InverseCase("SvyatoSlav"), "sVYATOsLAV"); + } + + [Fact] + public void ShiftIncTest() + { + Assert.Equal(RicksMercilessEncryptor.ShiftInc("abc"), "bcd"); + } + + [Fact] + public void GetUsedObjectsTest() + { + var expected = (new List() {12341234}).ToImmutableList(); + Assert.Equal(RicksMercilessEncryptor.GetUsedObjects("¶1234:1234¶"), expected); + Assert.Equal(RicksMercilessEncryptor.GetUsedObjects("¶1234:1234¶ //some stuff ¶1111:1111¶"), + expected); + Assert.Equal(RicksMercilessEncryptor.GetUsedObjects("¶1234:1234¶ /*some stuff ¶1111:1111¶ \n ¶1212:1212¶*/"), + expected); + } } } 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..9d246793 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 + net5.0 false @@ -12,4 +12,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..19f27fab --- /dev/null +++ b/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub/Program.cs @@ -0,0 +1,66 @@ +using System.Text; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Columns; +using BenchmarkDotNet.Configs; +using BenchmarkDotNet.Exporters.Csv; +using BenchmarkDotNet.Loggers; +using BenchmarkDotNet.Running; + + +namespace WubbaLubbaDubDub +{ + [Config(typeof(BenchmarkConfig))] + public class MyBenchmark + { + + private class BenchmarkConfig : ManualConfig + { + public BenchmarkConfig() + { + AddColumn(StatisticColumn.Mean); + AddColumn(StatisticColumn.Median); + AddColumn(StatisticColumn.StdDev); + AddColumn(StatisticColumn.Max); + AddLogger(ConsoleLogger.Default); + AddExporter(CsvExporter.Default); + // UnionRule = ConfigUnionRule.AlwaysUseLocal; + } + } + + private readonly string _data = new string('a', 10000); + + [Benchmark(Description = "String.Join()")] + public string TestJoin() + { + return string.Join("", _data.ToCharArray()); + } + + [Benchmark(Description = "TestBuilder")] + public string TestBuilder() + { + var testStringBuilder = new StringBuilder(""); + + foreach (var sym in _data.ToCharArray()) + { + testStringBuilder.Append(sym); + } + + return testStringBuilder.ToString(); + } + + [Benchmark(Description = "Concat")] + public string TestConcat() + { + return string.Concat(_data.ToCharArray()); + } + } + + public class Program + { + private static void Main() + { + var result = BenchmarkRunner.Run(); + } + } + +} \ No newline at end of file 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..375a004c 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,8 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Linq; +using System.Text.RegularExpressions; namespace WubbaLubbaDubDub { @@ -12,7 +14,7 @@ public static class RicksMercilessEncryptor public static string[] SplitToLines(this string text) { // У строки есть специальный метод. Давай здесь без регулярок - throw new NotImplementedException(); + return text.Split('\n'); } /// @@ -21,7 +23,7 @@ public static string[] SplitToLines(this string text) public static string[] SplitToWords(this string line) { // А вот здесь поиграйся с регулярками. - throw new NotImplementedException(); + return Regex.Split(line, @"\W+"); } /// @@ -31,7 +33,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 +42,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 +51,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 +67,18 @@ public static string CharsToCodes(this string s) FYI: локальную функцию можно объявлять даже после строки с return. То же самое можно сделать и для всех оставшихся методов. */ - throw new NotImplementedException(); + string CharToCode(char ch) { + return String.Format("\\u{0:x4}", (int)ch); + } + + var chars = s.ToCharArray(); + var codes = new string[s.Length]; + for (int i = 0; i < s.Length; ++i) + { + codes[i] = CharToCode(chars[i]); + } + + return String.Concat(codes); } /// @@ -77,7 +90,7 @@ public static string GetReversed(this string s) Собрать строку из последовательности строк можно несколькими способами. Один из низ - статический метод Concat. Но ты можешь выбрать любой. */ - throw new NotImplementedException(); + return String.Concat(s.Reverse()); } /// @@ -90,7 +103,21 @@ public static string InverseCase(this string s) На минуту задержись здесь и посмотри, какие еще есть статические методы у char. Например, он содержит методы-предикаты для определения категории Юникода символа, что очень удобно. */ - throw new NotImplementedException(); + var strWithReversedCase = new char[s.Length]; + var chars = s.ToCharArray(); + + for (int i = 0; i < s.Length; ++i) + { + if (char.IsUpper(s[i])) { + strWithReversedCase[i] = char.ToLower(chars[i]); + } + else + { + strWithReversedCase[i] = char.ToUpper(chars[i]); + } + } + + return String.Concat(strWithReversedCase); } /// @@ -99,7 +126,15 @@ public static string InverseCase(this string s) /// public static string ShiftInc(this string s) { - throw new NotImplementedException(); + var shiftedStr = new char[s.Length]; + var chars = s.ToCharArray(); + + for (int i = 0; i < s.Length; ++i) + { + shiftedStr[i] = (char)(chars[i] + 1); + } + + return String.Concat(shiftedStr); } @@ -117,7 +152,22 @@ public static IImmutableList GetUsedObjects(this string text) Задача на поиграться с регулярками - вся сложность в том, чтобы аккуратно игнорировать комментарии. Экспериментировать онлайн можно, например, здесь: http://regexstorm.net/tester и https://regexr.com/ */ - throw new NotImplementedException(); + // Обычный Replace не умеет работать с регулярками.((( + var withoutComments = Regex.Replace(text, @"\/\/.*", string.Empty); // убрали строчные комменты + withoutComments = Regex.Replace( + withoutComments, @"\/\*[^(\*\/)]*\*\/", string.Empty + ); // убрали блочные комменты + + var matches = Regex.Matches(withoutComments, @"¶\w{4}:\w{4}¶"); + var identifiers = new List(); + + foreach (var match in matches) + { + var convertedMatch = Regex.Replace(match.ToString(), @"[¶:]", string.Empty); + identifiers.Add(Convert.ToInt64(convertedMatch)); + } + + return identifiers.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..66106229 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,13 @@ - netcoreapp2.0 + net5.0 + false + + + + + diff --git a/course-2021-1/exercises/05-drunk-fibonacci/DrunkFibonacci/DrunkFibonacci/DrunkFibonacci.cs b/course-2021-1/exercises/05-drunk-fibonacci/DrunkFibonacci/DrunkFibonacci/DrunkFibonacci.cs index ac217f0d..18dc8423 100644 --- a/course-2021-1/exercises/05-drunk-fibonacci/DrunkFibonacci/DrunkFibonacci/DrunkFibonacci.cs +++ b/course-2021-1/exercises/05-drunk-fibonacci/DrunkFibonacci/DrunkFibonacci/DrunkFibonacci.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; namespace DrunkFibonacci { @@ -12,7 +13,7 @@ internal static class DrunkFibonacci public static int[] CreateIntArray(int len) { // на создание массивов заданной длины - throw new NotImplementedException(); + return new int[len]; } /// @@ -24,7 +25,10 @@ public static int[] CreateIntArray(int len) public static void FillIntArray(int[] arr, int seed, int step) { // на задание значений массива - throw new NotImplementedException(); + arr[0] = seed; + for (int i = 1; i < arr.Length; ++i) { + arr[i] = arr[i - 1] + step; + } } /// @@ -34,7 +38,7 @@ public static void FillIntArray(int[] arr, int seed, int step) public static int[] GetFirstFiveFibonacci() { // на создание массива с инициализацией - throw new NotImplementedException(); + return new int[] {1, 1, 2, 3, 5}; } /// @@ -49,11 +53,17 @@ public static IEnumerable GetDeterministicRandomSequence() Задача на ленивую генерацию последовательностей. */ - throw new NotImplementedException(); + var randomGenerator = new Random(42); + + while (true) + { + yield return randomGenerator.Next(); + } } /// - /// Возвращает последовательность Фибоначчи, которая слегка перебрала и теперь путается, что-то забывает или по десятому разу рассказывает одни и те же шутки :) + /// Возвращает последовательность Фибоначчи, которая слегка перебрала и теперь путается, + /// что-то забывает или по десятому разу рассказывает одни и те же шутки :) /// public static IEnumerable GetDrunkFibonacci() { @@ -67,7 +77,37 @@ public static IEnumerable GetDrunkFibonacci() из последовательности GetDeterministicRandomSequence и проверяешь, есть ли у числа Y единичные биты числа 42. При вычислении сложения переполнение типа разрешено и всячески поощряется. */ - throw new NotImplementedException(); + var i = 0; + var prev = 0; + var prevPrev = 0; + var curNum = 1; + + foreach (var rand_seq_elem in GetDeterministicRandomSequence()) + { + i += 1; + prevPrev = prev; + prev = curNum; + curNum = prev + prevPrev; + + if (i < 3) + { + curNum = 1; + } + else if (i % 6 == 0) + { + continue; + } else if (i % 6 == 4) + { + curNum = 300; + } + + // В условии неточность: непонятно, что понимают под "есть ли биты числа 42". Будем считать, что + // имелось в виду, есть ли хоть какие-то биты числа 42 в curNum. + bool cond = (rand_seq_elem & 42) > 0; + curNum = cond ? (curNum & ~42) : curNum; + + yield return curNum; + } } /// @@ -77,18 +117,20 @@ public static IEnumerable GetDrunkFibonacci() /// Длина отрезка. public static int GetMaxOnRange(int from, int cnt) { - // научишься пропускать и брать фиксированную часть последовательности, агрегировать. Максимум есть среди готовых функций агрегации. - throw new NotImplementedException(); + // научишься пропускать и брать фиксированную часть последовательности, агрегировать. + // Максимум есть среди готовых функций агрегации. + return GetDrunkFibonacci().Skip(from).Take(cnt).Max(); } /// - /// Возвращает следующий отрезок из отрицательных значений последовательности DrunkFibonacci в виде списка, начиная поиск с индекса . + /// Возвращает следующий отрезок из отрицательных значений последовательности DrunkFibonacci в виде списка, + /// начиная поиск с индекса . /// /// Индекс начала поиска отрезка. Нумерация с единицы. public static List GetNextNegativeRange(int from = 1) { // научишься пропускать и брать по условию, превращать в список (см. ToList). - throw new NotImplementedException(); + return GetDrunkFibonacci().Skip(from).SkipWhile(x => x >= 0).TakeWhile(x => x < 0).ToList(); // следующий??? } /// @@ -97,7 +139,9 @@ public static List GetNextNegativeRange(int from = 1) public static IEnumerable GetXoredWithLaggedItself() { // узнаешь о существовании функции Zip. - throw new NotImplementedException(); + return GetDrunkFibonacci().Zip( + GetDrunkFibonacci().Skip(42), (first, second) => first ^ second + ); } /// @@ -106,7 +150,18 @@ public static IEnumerable GetXoredWithLaggedItself() public static IEnumerable GetInChunks() { // ни чему особо не научишься, просто интересная задачка :) - throw new NotImplementedException(); + var chunk = new int[16]; + var i = 0; + + foreach(var curNum in GetDrunkFibonacci()) { + chunk[i] = curNum; + if (i == 15) { + yield return chunk; + i = 0; + } else { + ++i; + } + } } /// @@ -122,7 +177,7 @@ public static IEnumerable FlattenChunkedSequence() Вообще говоря, SelectMany умеет много чего и мегаполезна. Она в какой-то степени эквивалентна оператору `bind` над монадами (в данном случае над монадами последовательностей). */ - throw new NotImplementedException(); + return GetInChunks().SelectMany(chunk => chunk.OrderBy(x => x).Take(3)); } /// @@ -131,7 +186,8 @@ public static IEnumerable FlattenChunkedSequence() /// /// /// Класс вычетов - мн-во значений, имеющих одинаковый остаток от деления на нек-е число (в данном случае 8). - /// В общем на выходе словарь пар, где ключ - остаток от деления на 8, а значение - кол-во элементов с таким остатком среди первых 10000 элементов посл-ти. + /// В общем на выходе словарь пар, где ключ - остаток от деления на 8, + /// а значение - кол-во элементов с таким остатком среди первых 10000 элементов посл-ти. /// public static Dictionary GetGroupSizes() { @@ -146,8 +202,9 @@ public static Dictionary GetGroupSizes() что и быстрее, и требует передачи меньшего кол-ва данных. Если у объекта, полученного вызовом .GroupBy дважды вызвать методы, инициирующие итерацию, то она будет произведена дважды. - Второй - не ленивый и производит непосредственно саму группировку. Можно трактовать это как "промежуточное кэширование" группировки для быстрого - [и возможно повторного] доступа к группам. Т.е. ты один раз произвел группировку, дальше пользуешься уже ей отдельно от оригинальной последовательности - + Второй - не ленивый и производит непосредственно саму группировку. Можно трактовать это как + "промежуточное кэширование" группировки для быстрого [и возможно повторного] доступа к группам. + Т.е. ты один раз произвел группировку, дальше пользуешься уже ей отдельно от оригинальной последовательности - это не потребует повторных итераций по ней. По сути ILookup аналогичен IDictionary> - разница лишь в том, что обращение к несуществующему ключу лукапа будет выдавать пустую последовательность, в то время как словарь сгенерирует исключение. @@ -156,7 +213,14 @@ public static Dictionary GetGroupSizes() Итого научишься группировать и создавать на их основе словарь (см. ToDictionary). */ - throw new NotImplementedException(); + return GetDrunkFibonacci().Take(10000) + .GroupBy( + x => x % 8, + (x_res_class, x) => new { + Key = x_res_class, + Count = x.Count() + } + ).ToDictionary(x => x.Key, x => x.Count); } } } diff --git a/course-2021-1/exercises/05-drunk-fibonacci/DrunkFibonacci/DrunkFibonacci/DrunkFibonacci.csproj b/course-2021-1/exercises/05-drunk-fibonacci/DrunkFibonacci/DrunkFibonacci/DrunkFibonacci.csproj index ce1697ae..20827042 100644 --- a/course-2021-1/exercises/05-drunk-fibonacci/DrunkFibonacci/DrunkFibonacci/DrunkFibonacci.csproj +++ b/course-2021-1/exercises/05-drunk-fibonacci/DrunkFibonacci/DrunkFibonacci/DrunkFibonacci.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp2.0 + net5.0 diff --git a/course-2021-1/exercises/05-drunk-fibonacci/DrunkFibonacci/DrunkFibonacci/Program.cs b/course-2021-1/exercises/05-drunk-fibonacci/DrunkFibonacci/DrunkFibonacci/Program.cs index 4cdf0912..0c9c3ff4 100644 --- a/course-2021-1/exercises/05-drunk-fibonacci/DrunkFibonacci/DrunkFibonacci/Program.cs +++ b/course-2021-1/exercises/05-drunk-fibonacci/DrunkFibonacci/DrunkFibonacci/Program.cs @@ -9,6 +9,9 @@ private static void Main() { Console.WriteLine("Hello World!"); + var arr = DrunkFibonacci.CreateIntArray(5); + DrunkFibonacci.FillIntArray(arr, 0, 5); + Console.WriteLine("FillIntArray: " + string.Join(',', arr)); Console.WriteLine("GetDrunkFibonacci: " + string.Join(',', DrunkFibonacci.GetDrunkFibonacci().Take(100))); Console.WriteLine("GetMaxOnRange: " + DrunkFibonacci.GetMaxOnRange(1000, 400)); Console.WriteLine("GetNextNegativeRange: " + string.Join(',', DrunkFibonacci.GetNextNegativeRange().Take(100))); diff --git a/course-2021-1/exercises/05-drunk-fibonacci/DrunkFibonacci/Results.txt b/course-2021-1/exercises/05-drunk-fibonacci/DrunkFibonacci/Results.txt new file mode 100644 index 00000000..3e85e9f6 --- /dev/null +++ b/course-2021-1/exercises/05-drunk-fibonacci/DrunkFibonacci/Results.txt @@ -0,0 +1,11 @@ +Hello World! +FillIntArray: 0,5,10,15,20 +GetDrunkFibonacci: 1,1,0,260,260,772,1284,2048,260,2308,4868,7428,12288,260,12548,25348,38148,63496,260,63748,127748,191748,319488,300,319748,639764,959812,1599568,260,1599828,3199876,4799956,7999824,260,8000084,16000388,24000724,40001112,300,40001412,80003092,120004804,200007888,260,200008148,400016516,600024916,1000041424,260,1000041684,2000083588,-1294841772,705241808,260,705242068,1410484356,2115726676,-768756264,260,-768756012,-1537511804,1988699732,451187920,260,451188180,902376580,1353565012,-2039025704,260,-2039025452,216916612,-1822108588,-1605191984,260,-1605191724,1084584108,-520607356,563976720,260,563976980,1127954180,1691931412,-1475081704,260,-1475081452,1344804612,-130276588,1214528016,260,1214528276,-1865910524,-651381996,1777674776,260,1777675028,-739617020,1038058260,298441232,260,298441492 +GetMaxOnRange: 2131407812 +GetNextNegativeRange: -1294841772 +GetXoredWithLaggedItself: 200007889,261,200008148,400016768,600024656,1000040660,1024,1000039636,2000083840,-1294843568,705245652,7168,705237972,1410484608,2115722320,-768747812,37888,-768782628,-1537511552,1988747088,451241940,191488,450917844,902376872,1353261648,-2038485812,959552,-2039572348,216916864,-1820541696,-1604164268,4799696,-1607948668,1084584360,-528335920,560578452,24000976,603964748,1127953960,1723501712,-1395602932,120005056,-1543509052,1344804352,-203963712,1605631636,600024656,1946112196,-1865910784,-491266112,516157596,-1294841520,1140591044,-739617280,399941824,1172017812,2115726416,-1008439604,596882944,-412080704,-55958380,1988700024,1108729796,-1310550448,272070208,-1988143508,1353564792,985699276,2037184592,-1336572352,-1552052924,-1822108336,264422932,1595990912,-1360796784,762791532,-520607616,1280290260,-609980024,1760244288,1713385188,1691931152,-1928392452,1245067200,-951756360,-374366636,-130276848,-236736444,1930368128,1693621184,258851164,-651382256,-162489012,1061908096,-1224471360,-841564076,1038058000,267731524,1014575272,1266421776 +GetInChunks: [1,1,0,260,260,772,1284,2048,260,2308,4868,7428,12288,260,12548,25348] +[38148,63496,260,63748,127748,191748,319488,300,319748,639764,959812,1599568,260,1599828,3199876,4799956] +[7999824,260,8000084,16000388,24000724,40001112,300,40001412,80003092,120004804,200007888,260,200008148,400016516,600024916,1000041424] +FlattenChunkedSequence: 0,1,1,260,260,300,260,260,300,-1537511804,-1294841772,-768756264,-2039025704,-2039025452,-1822108588,-1865910524,-1475081704,-1475081452,-1310550188,-1128891672,-1128891372,-1349488704,-1349488444,-1182299824,-1758528368,-1616529832,-1616529580,-2027044972,-1758528108,-1013522880,-2136243008,-2136242748,-2113760428,-1978866412,-1866455024,-1866454764,-1378582208,-1378581948,-900915308,-1572059756,-1077971056,-1048039932,-1602329528,-1602329276,-1179459776,-1403520440,-1403520188,-1150297724,-2053263484,-1456520316,-1026632120,-1694633408,-1676381820,-838191296,-1694633148,-1375715000,-788931628,-1375714748,-872243324,-165620672 +GetGroupSizes: [1, 2],[0, 2000],[4, 5094],[-4, 2904]