Browse Source

Solved day 4

dhasenan 3 years ago
parent
commit
e523b3ccf0
2 changed files with 191 additions and 0 deletions
  1. 1
    0
      dub.sdl
  2. 190
    0
      source/advent/day4.d

+ 1
- 0
dub.sdl View File

@@ -3,3 +3,4 @@ description "A minimal D application."
3 3
 authors "Neia Neutuladh"
4 4
 copyright "Copyright © 2018, Neia Neutuladh"
5 5
 license "proprietary"
6
+dependency "datefmt" version="*"

+ 190
- 0
source/advent/day4.d View File

@@ -0,0 +1,190 @@
1
+module advent.day4;
2
+
3
+import std.stdio;
4
+import std.algorithm, std.string, std.conv;
5
+import std.datetime;
6
+import std.range;
7
+import std.typecons;
8
+import advent.core;
9
+import datefmt;
10
+
11
+Advent getAdvent() { return new GuardSource; }
12
+
13
+class GuardSource : Advent
14
+{
15
+    override string part1(string data)
16
+    {
17
+        auto events = munge(data);
18
+        auto solution = solvePart1(events);
19
+        writefln("guard %s asleep most at 00:%s", solution[0], solution[1]);
20
+        return (solution[0] * solution[1]).to!string;
21
+    }
22
+
23
+    override string part2(string data)
24
+    {
25
+        auto events = munge(data);
26
+
27
+        int bestId;
28
+        int bestCount;
29
+        size_t bestMinute;
30
+        foreach (guard; events.map!(x => x.guardId).uniq)
31
+        {
32
+            auto times = findSleepTimes(events, guard);
33
+            foreach (minute; 0..times.length)
34
+            {
35
+                if (times[minute] > bestCount)
36
+                {
37
+                    bestCount = times[minute];
38
+                    bestId = guard;
39
+                    bestMinute = minute;
40
+                    writefln("guard %s asleep %s times at minute %s", guard, times[minute], minute);
41
+                }
42
+            }
43
+        }
44
+
45
+        return (bestId * bestMinute).to!string;
46
+    }
47
+
48
+    Tuple!(int, int) solvePart1(Event[] events)
49
+    {
50
+        Duration bestTime;
51
+        int bestId;
52
+
53
+        foreach (pair; events.chunkBy!(x => x.guardId))
54
+        {
55
+            Duration current;
56
+            auto group = pair[1].array;
57
+            assert(group.length % 2 == 0);
58
+            for (int i = 0; i < group.length; i += 2)
59
+            {
60
+                auto sleep = group[i];
61
+                auto wake = group[i + 1];
62
+                assert(sleep.type == Event.Type.sleep);
63
+                assert(wake.type == Event.Type.wake);
64
+                current += (wake.time - sleep.time);
65
+            }
66
+            if (current > bestTime)
67
+            {
68
+                bestTime = current;
69
+                bestId = pair[0];
70
+            }
71
+        }
72
+
73
+        auto sleeptimes = findSleepTimes(events, bestId);
74
+        int bestMinute, bestCount;
75
+        foreach (minute; 0..60)
76
+        {
77
+            if (sleeptimes[minute] >= bestCount)
78
+            {
79
+                bestMinute = minute;
80
+                bestCount = sleeptimes[minute];
81
+            }
82
+        }
83
+
84
+        writefln("guard %s asleep most minutes, and most asleep at %s", bestId, bestMinute);
85
+
86
+        return tuple(bestId, bestMinute);
87
+    }
88
+
89
+    int[60] findSleepTimes(Event[] events, int guardId)
90
+    {
91
+        int[60] sleeptimes;
92
+        auto f = events.filter!(x => x.guardId == guardId);
93
+        while (!f.empty)
94
+        {
95
+            auto a = f.front;
96
+            f.popFront;
97
+            auto b = f.front;
98
+            f.popFront;
99
+            assert(a.type == Event.Type.sleep);
100
+            assert(b.type == Event.Type.wake);
101
+            foreach (minute; a.time.minute .. b.time.minute)
102
+            {
103
+                sleeptimes[minute]++;
104
+            }
105
+        }
106
+        return sleeptimes;
107
+    }
108
+}
109
+
110
+auto munge(string data)
111
+{
112
+    auto a = data.splitter("\n")
113
+        .map!(x => x.strip)
114
+        .filter!(x => x.length > 0)
115
+        .map!(x => Event.parse(x))
116
+        .array;
117
+    sort(a);
118
+    int mostRecentGuard = -1;
119
+    foreach (ref event; a)
120
+    {
121
+        if (event.guardId >= 0)
122
+        {
123
+            mostRecentGuard = event.guardId;
124
+        }
125
+        else
126
+        {
127
+            assert(mostRecentGuard >= 0);
128
+            event.guardId = mostRecentGuard;
129
+        }
130
+    }
131
+    a = a.filter!(x => x.type != Event.Type.start).array;
132
+    a.sort!(
133
+            (a, b) =>
134
+                (a.guardId < b.guardId) ||
135
+                (a.guardId == b.guardId && a.time < b.time));
136
+    return a;
137
+}
138
+
139
+struct Event
140
+{
141
+    enum Type { start, sleep, wake }
142
+    Type type;
143
+    int guardId = -1;
144
+    SysTime time;
145
+
146
+    int opCmp(const ref Event other) const
147
+    {
148
+        return time.opCmp(other.time);
149
+    }
150
+
151
+    static Event parse(string line)
152
+    {
153
+        // [1518-08-16 00:03] Guard #1399 begins shift
154
+        Event event;
155
+        auto parts = line.strip.split("] ");
156
+        event.time = parseTime(parts[0].strip.chomp("["));
157
+        switch (parts[1].strip)
158
+        {
159
+            case "wakes up":
160
+                event.type = Type.wake;
161
+                break;
162
+            case "falls asleep":
163
+                event.type = Type.sleep;
164
+                break;
165
+            default:
166
+                event.type = Type.start;
167
+                event.guardId = parts[1].splitter("#").drop(1).front.splitter(" ").front.to!int;
168
+                break;
169
+        }
170
+        return event;
171
+    }
172
+
173
+    private static SysTime parseTime(string s)
174
+    {
175
+        import std.stdio;
176
+        s = s.strip;
177
+        if (s[0] == '[') s = s[1..$];
178
+        return datefmt.parse(s.strip, "%Y-%m-%d %H:%M");
179
+    }
180
+}
181
+
182
+unittest
183
+{
184
+    auto time = Event.parseTime("1518-01-12 00:03");
185
+    assert(time.year == 1518);
186
+    assert(time.month == 1);
187
+    assert(time.day == 12);
188
+    assert(time.hour == 0);
189
+    assert(time.minute == 3);
190
+}