diff --git a/AdventOfCode2018.Tests/AdventOfCode2018.Tests.csproj b/AdventOfCode2018.Tests/AdventOfCode2018.Tests.csproj index f87a768..f7c0d7c 100644 --- a/AdventOfCode2018.Tests/AdventOfCode2018.Tests.csproj +++ b/AdventOfCode2018.Tests/AdventOfCode2018.Tests.csproj @@ -61,6 +61,7 @@ + diff --git a/AdventOfCode2018.Tests/GuardEvent_Tests.cs b/AdventOfCode2018.Tests/GuardEvent_Tests.cs new file mode 100644 index 0000000..9431704 --- /dev/null +++ b/AdventOfCode2018.Tests/GuardEvent_Tests.cs @@ -0,0 +1,134 @@ +using System.Collections.Generic; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace AdventOfCode2018.Tests +{ + [TestClass()] + public class GuardEvent_Tests + { + #region FromString + + [TestMethod()] + public void FromString__ShiftBegin() + { + GuardEvent guardEvent = GuardEvent.FromString("[1518-11-01 00:00] Guard #10 begins shift"); + + Assert.AreEqual(10, guardEvent.ID); + Assert.AreEqual(11, guardEvent.Date.Month); + Assert.AreEqual(1, guardEvent.Date.Day); + Assert.AreEqual(0, guardEvent.Date.Hour); + Assert.AreEqual(0, guardEvent.Date.Minute); + Assert.AreEqual(GuardEventType.ShiftBegin, guardEvent.Type); + } + + [TestMethod()] + public void FromString__FallSleep() + { + GuardEvent guardEvent = GuardEvent.FromString("[1518-11-02 00:40] falls asleep"); + + Assert.AreEqual(null, guardEvent.ID); + Assert.AreEqual(11, guardEvent.Date.Month); + Assert.AreEqual(2, guardEvent.Date.Day); + Assert.AreEqual(0, guardEvent.Date.Hour); + Assert.AreEqual(40, guardEvent.Date.Minute); + Assert.AreEqual(GuardEventType.FallSleep, guardEvent.Type); + } + + [TestMethod()] + public void FromString__WakeUp() + { + GuardEvent guardEvent = GuardEvent.FromString("[1518-11-03 00:29] wakes up"); + + Assert.AreEqual(null, guardEvent.ID); + Assert.AreEqual(11, guardEvent.Date.Month); + Assert.AreEqual(3, guardEvent.Date.Day); + Assert.AreEqual(0, guardEvent.Date.Hour); + Assert.AreEqual(29, guardEvent.Date.Minute); + Assert.AreEqual(GuardEventType.WakeUp, guardEvent.Type); + } + + #endregion FromString + + #region FromStringArray + + [TestMethod()] + public void FromStringArray__TestBase() + { + List guardEvents = GuardEvent.FromStringArray(new string[] { + "[1518-11-01 00:00] Guard #10 begins shift", + "[1518-11-01 00:05] falls asleep", + "[1518-11-01 00:25] wakes up", + "[1518-11-01 00:30] falls asleep", + "[1518-11-01 00:55] wakes up", + "[1518-11-01 23:58] Guard #99 begins shift", + "[1518-11-02 00:40] falls asleep", + "[1518-11-02 00:50] wakes up", + }); + + Assert.AreEqual(10, guardEvents[0].ID); + Assert.AreEqual(GuardEventType.ShiftBegin, guardEvents[0].Type); + + Assert.AreEqual(10, guardEvents[1].ID); + Assert.AreEqual(GuardEventType.FallSleep, guardEvents[1].Type); + + Assert.AreEqual(10, guardEvents[2].ID); + Assert.AreEqual(GuardEventType.WakeUp, guardEvents[2].Type); + + Assert.AreEqual(10, guardEvents[3].ID); + Assert.AreEqual(GuardEventType.FallSleep, guardEvents[3].Type); + + Assert.AreEqual(10, guardEvents[4].ID); + Assert.AreEqual(GuardEventType.WakeUp, guardEvents[4].Type); + + Assert.AreEqual(99, guardEvents[5].ID); + Assert.AreEqual(GuardEventType.ShiftBegin, guardEvents[5].Type); + + Assert.AreEqual(99, guardEvents[6].ID); + Assert.AreEqual(GuardEventType.FallSleep, guardEvents[6].Type); + + Assert.AreEqual(99, guardEvents[7].ID); + Assert.AreEqual(GuardEventType.WakeUp, guardEvents[7].Type); + } + + [TestMethod()] + public void FromStringArray__TestBaseUnsorted() + { + List guardEvents = GuardEvent.FromStringArray(new string[] { + "[1518-11-01 00:00] Guard #10 begins shift", + "[1518-11-01 23:58] Guard #99 begins shift", + "[1518-11-01 00:30] falls asleep", + "[1518-11-02 00:40] falls asleep", + "[1518-11-01 00:05] falls asleep", + "[1518-11-02 00:50] wakes up", + "[1518-11-01 00:55] wakes up", + "[1518-11-01 00:25] wakes up", + }); + + Assert.AreEqual(10, guardEvents[0].ID); + Assert.AreEqual(GuardEventType.ShiftBegin, guardEvents[0].Type); + + Assert.AreEqual(10, guardEvents[1].ID); + Assert.AreEqual(GuardEventType.FallSleep, guardEvents[1].Type); + + Assert.AreEqual(10, guardEvents[2].ID); + Assert.AreEqual(GuardEventType.WakeUp, guardEvents[2].Type); + + Assert.AreEqual(10, guardEvents[3].ID); + Assert.AreEqual(GuardEventType.FallSleep, guardEvents[3].Type); + + Assert.AreEqual(10, guardEvents[4].ID); + Assert.AreEqual(GuardEventType.WakeUp, guardEvents[4].Type); + + Assert.AreEqual(99, guardEvents[5].ID); + Assert.AreEqual(GuardEventType.ShiftBegin, guardEvents[5].Type); + + Assert.AreEqual(99, guardEvents[6].ID); + Assert.AreEqual(GuardEventType.FallSleep, guardEvents[6].Type); + + Assert.AreEqual(99, guardEvents[7].ID); + Assert.AreEqual(GuardEventType.WakeUp, guardEvents[7].Type); + } + + #endregion FromStringArray + } +} \ No newline at end of file diff --git a/AdventOfCode2018/Day04.cs b/AdventOfCode2018/Day04.cs index a5a313d..c132faf 100644 --- a/AdventOfCode2018/Day04.cs +++ b/AdventOfCode2018/Day04.cs @@ -1,4 +1,8 @@ -namespace AdventOfCode2018 +using System; +using System.Collections.Generic; +using System.Linq; + +namespace AdventOfCode2018 { /* --- Day 4: Repose Record --- @@ -59,12 +63,185 @@ { public string ResolvePart1(string[] inputs) { - return null; + List guardEvents = GuardEvent.FromStringArray(inputs); + Dictionary dictFullHistogram = BuildFullHistorgram(guardEvents); + + // Find sleepier guard + GuardSleepHistogram highestSleeperHistogram = null; + long highestTotalSleep = long.MinValue; + foreach (GuardSleepHistogram guardHistogram in dictFullHistogram.Values) + { + int totalSleep = guardHistogram.SleepOnMunute.Sum(); + + if (totalSleep > highestTotalSleep) + { + highestSleeperHistogram = guardHistogram; + highestTotalSleep = totalSleep; + } + } + + // Find sleepier minute + int maxSleepMinute = int.MinValue; + int maxSleepMinuteValue = int.MinValue; + for (int i = 0; i < GuardSleepHistogram.MinutesOnHour; i++) + { + if (highestSleeperHistogram.SleepOnMunute[i] > maxSleepMinuteValue) + { + maxSleepMinute = i; + maxSleepMinuteValue = highestSleeperHistogram.SleepOnMunute[i]; + } + } + + int result = highestSleeperHistogram.ID * maxSleepMinute; + return result.ToString(); } public string ResolvePart2(string[] inputs) { return null; } + + private static Dictionary BuildFullHistorgram(List guardEvents) + { + Dictionary dictFullHistogram = new Dictionary(); + foreach (IGrouping group in guardEvents.GroupBy(guardEvent => guardEvent.Date.DayOfYear)) + { + Dictionary dictDayHistogram = new Dictionary(); + foreach (GuardEvent guardEvent in group) + { + if (guardEvent.ID == null) { continue; } + GuardSleepHistogram dayGuardHistogram = null; + if (dictDayHistogram.ContainsKey((int)guardEvent.ID)) + { + dayGuardHistogram = dictDayHistogram[(int)guardEvent.ID]; + } + else + { + dayGuardHistogram = new GuardSleepHistogram { ID = (int)guardEvent.ID }; + dictDayHistogram.Add(dayGuardHistogram.ID, dayGuardHistogram); + } + if (guardEvent.Type == GuardEventType.FallSleep) + { + dayGuardHistogram.FallSleep(guardEvent.Date.Minute); + } + if (guardEvent.Type == GuardEventType.WakeUp) + { + dayGuardHistogram.WakeUp(guardEvent.Date.Minute); + } + } + + foreach (GuardSleepHistogram dayGuardHistogram in dictDayHistogram.Values) + { + GuardSleepHistogram guardHistogram = null; + if (dictFullHistogram.ContainsKey(dayGuardHistogram.ID)) + { + guardHistogram = dictFullHistogram[dayGuardHistogram.ID]; + guardHistogram.AddHistogram(dayGuardHistogram); + } + else + { + dictFullHistogram.Add(dayGuardHistogram.ID, dayGuardHistogram); + } + } + } + + return dictFullHistogram; + } + } + + public enum GuardEventType + { + ShiftBegin, + FallSleep, + WakeUp, + } + + public class GuardEvent + { + public DateTime Date { get; set; } + public int? ID { get; set; } + public GuardEventType Type { get; set; } + + public static GuardEvent FromString(string strEvent) + { + GuardEvent guardEvent = new GuardEvent(); + string[] parts = strEvent.Split(new string[] { "[", "-", " ", ":", "]", "#", }, StringSplitOptions.RemoveEmptyEntries); + guardEvent.Date = new DateTime( + Convert.ToInt32(parts[0]), + Convert.ToInt32(parts[1]), + Convert.ToInt32(parts[2]), + Convert.ToInt32(parts[3]), + Convert.ToInt32(parts[4]), + 0 + ); + if (parts[5] == "Guard") + { + guardEvent.ID = Convert.ToInt32(parts[6]); + guardEvent.Type = GuardEventType.ShiftBegin; + } + if (parts[5] == "falls") + { + guardEvent.Type = GuardEventType.FallSleep; + } + if (parts[5] == "wakes") + { + guardEvent.Type = GuardEventType.WakeUp; + } + return guardEvent; + } + + public static List FromStringArray(string[] strEvents) + { + List guardEvents = strEvents + .Select(strEvent => FromString(strEvent)) + .OrderBy(guardEvent => guardEvent.Date) + .ToList(); + + int? guardID = null; + foreach (GuardEvent guardEvent in guardEvents) + { + if (guardEvent.Type == GuardEventType.ShiftBegin) + { + guardID = guardEvent.ID; + } + else + { + guardEvent.ID = guardID; + } + } + + return guardEvents; + } + } + + public class GuardSleepHistogram + { + public const int MinutesOnHour = 60; + public int ID { get; set; } + public int[] SleepOnMunute { get; } = new int[MinutesOnHour]; + + public void FallSleep(int minute) + { + for (int i = minute; i < MinutesOnHour; i++) + { + SleepOnMunute[i] = 1; + } + } + + public void WakeUp(int minute) + { + for (int i = minute; i < MinutesOnHour; i++) + { + SleepOnMunute[i] = 0; + } + } + + public void AddHistogram(GuardSleepHistogram histogram) + { + for (int i = 0; i < MinutesOnHour; i++) + { + SleepOnMunute[i] += histogram.SleepOnMunute[i]; + } + } } }