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]