Compare commits
30
Commits
66d47e2a49
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8062f0a2be | ||
|
|
5531412a55 | ||
|
|
14c93b8482 | ||
|
|
d511a8cd65 | ||
|
|
944fad0f02 | ||
|
|
3e711561fa | ||
|
|
949f3e7444 | ||
|
|
eff0e909a1 | ||
|
|
f373431d8e | ||
|
|
439760c9ec | ||
|
|
0ad73c41d9 | ||
|
|
4ee98ff5fa | ||
|
|
cb807de984 | ||
|
|
96d9683eb2 | ||
|
|
200555b6cb | ||
|
|
62f65846c7 | ||
|
|
a57839a58a | ||
|
|
36f95e6f49 | ||
|
|
f5c7fe9189 | ||
|
|
c780f42f1d | ||
|
|
904a46cc3c | ||
|
|
6bff35b952 | ||
|
|
de4e101672 | ||
|
|
6ba10d386f | ||
|
|
538c76c1eb | ||
|
|
72bafa3d08 | ||
|
|
9802ed1f35 | ||
|
|
7da7595db4 | ||
|
|
9c6493b800 | ||
|
|
4a516b9e77 |
@@ -0,0 +1,990 @@
|
||||
+13
|
||||
-16
|
||||
+18
|
||||
+11
|
||||
+15
|
||||
+10
|
||||
-4
|
||||
-19
|
||||
+14
|
||||
-19
|
||||
-17
|
||||
-19
|
||||
-2
|
||||
+6
|
||||
+2
|
||||
+21
|
||||
+5
|
||||
+12
|
||||
-10
|
||||
-10
|
||||
+18
|
||||
-11
|
||||
+2
|
||||
+17
|
||||
-5
|
||||
+14
|
||||
+14
|
||||
-3
|
||||
-12
|
||||
+10
|
||||
+7
|
||||
-3
|
||||
+6
|
||||
-2
|
||||
+8
|
||||
-17
|
||||
-18
|
||||
-19
|
||||
-14
|
||||
+9
|
||||
-16
|
||||
-1
|
||||
-1
|
||||
+11
|
||||
-3
|
||||
+8
|
||||
-12
|
||||
+10
|
||||
+14
|
||||
+12
|
||||
-18
|
||||
+19
|
||||
-5
|
||||
+13
|
||||
+1
|
||||
+4
|
||||
+2
|
||||
+11
|
||||
-3
|
||||
-2
|
||||
+18
|
||||
+8
|
||||
-4
|
||||
+15
|
||||
-7
|
||||
-3
|
||||
+18
|
||||
+16
|
||||
+2
|
||||
-4
|
||||
-12
|
||||
-19
|
||||
-4
|
||||
+12
|
||||
+15
|
||||
-17
|
||||
+1
|
||||
-16
|
||||
-5
|
||||
+15
|
||||
+26
|
||||
+9
|
||||
+9
|
||||
-3
|
||||
-5
|
||||
+3
|
||||
+3
|
||||
-11
|
||||
-8
|
||||
-11
|
||||
-16
|
||||
+14
|
||||
+14
|
||||
+14
|
||||
+17
|
||||
+14
|
||||
+11
|
||||
-9
|
||||
+18
|
||||
-10
|
||||
-4
|
||||
-11
|
||||
-10
|
||||
-9
|
||||
+8
|
||||
+12
|
||||
-6
|
||||
-1
|
||||
-2
|
||||
+12
|
||||
-17
|
||||
-1
|
||||
+17
|
||||
-10
|
||||
+9
|
||||
+11
|
||||
+6
|
||||
+3
|
||||
+18
|
||||
+19
|
||||
+11
|
||||
-3
|
||||
+15
|
||||
-3
|
||||
-2
|
||||
+18
|
||||
+17
|
||||
+13
|
||||
+13
|
||||
-6
|
||||
+16
|
||||
+10
|
||||
+7
|
||||
-6
|
||||
-15
|
||||
-15
|
||||
-1
|
||||
+15
|
||||
+6
|
||||
-2
|
||||
-12
|
||||
+19
|
||||
-1
|
||||
+17
|
||||
+18
|
||||
-8
|
||||
-11
|
||||
-18
|
||||
+12
|
||||
-3
|
||||
-14
|
||||
+6
|
||||
-12
|
||||
+1
|
||||
-11
|
||||
-9
|
||||
+13
|
||||
-3
|
||||
-15
|
||||
-19
|
||||
-16
|
||||
-3
|
||||
+7
|
||||
+7
|
||||
-17
|
||||
-18
|
||||
+3
|
||||
-2
|
||||
-12
|
||||
-1
|
||||
+16
|
||||
+15
|
||||
+10
|
||||
+7
|
||||
-13
|
||||
+7
|
||||
+13
|
||||
+14
|
||||
+5
|
||||
+18
|
||||
-14
|
||||
-8
|
||||
-4
|
||||
+15
|
||||
-20
|
||||
-17
|
||||
-17
|
||||
+11
|
||||
-15
|
||||
-14
|
||||
-10
|
||||
-1
|
||||
+5
|
||||
-11
|
||||
+18
|
||||
-4
|
||||
-19
|
||||
+15
|
||||
-8
|
||||
+14
|
||||
-20
|
||||
-12
|
||||
+10
|
||||
-11
|
||||
-12
|
||||
+16
|
||||
-7
|
||||
-7
|
||||
+4
|
||||
-18
|
||||
-8
|
||||
+11
|
||||
+13
|
||||
-6
|
||||
+24
|
||||
+8
|
||||
+4
|
||||
-19
|
||||
+11
|
||||
+15
|
||||
+3
|
||||
-17
|
||||
+30
|
||||
+9
|
||||
+10
|
||||
+6
|
||||
-2
|
||||
+3
|
||||
+14
|
||||
+8
|
||||
-3
|
||||
-12
|
||||
+1
|
||||
+5
|
||||
-8
|
||||
+11
|
||||
+10
|
||||
+16
|
||||
+6
|
||||
+16
|
||||
+1
|
||||
+21
|
||||
+19
|
||||
+18
|
||||
+18
|
||||
+15
|
||||
+15
|
||||
+8
|
||||
+2
|
||||
-6
|
||||
-16
|
||||
+5
|
||||
-10
|
||||
+18
|
||||
-12
|
||||
+16
|
||||
+6
|
||||
+18
|
||||
-6
|
||||
-2
|
||||
+5
|
||||
-14
|
||||
-17
|
||||
-14
|
||||
-13
|
||||
-7
|
||||
+16
|
||||
-8
|
||||
-11
|
||||
-3
|
||||
+8
|
||||
-13
|
||||
+6
|
||||
+3
|
||||
-5
|
||||
+6
|
||||
+5
|
||||
+1
|
||||
+12
|
||||
+14
|
||||
+10
|
||||
+12
|
||||
-20
|
||||
+12
|
||||
-15
|
||||
+8
|
||||
+4
|
||||
-7
|
||||
-9
|
||||
-1
|
||||
+11
|
||||
-22
|
||||
-4
|
||||
-14
|
||||
-4
|
||||
-18
|
||||
+6
|
||||
+2
|
||||
+8
|
||||
-4
|
||||
-1
|
||||
+16
|
||||
-17
|
||||
-1
|
||||
-2
|
||||
-10
|
||||
-10
|
||||
-10
|
||||
+16
|
||||
+3
|
||||
-12
|
||||
+2
|
||||
-1
|
||||
+4
|
||||
-15
|
||||
+18
|
||||
-2
|
||||
-9
|
||||
-6
|
||||
-22
|
||||
+7
|
||||
+16
|
||||
-5
|
||||
+17
|
||||
+13
|
||||
+2
|
||||
-1
|
||||
+3
|
||||
-11
|
||||
+10
|
||||
-25
|
||||
-14
|
||||
+17
|
||||
-15
|
||||
+3
|
||||
+43
|
||||
+19
|
||||
+12
|
||||
+1
|
||||
-8
|
||||
+4
|
||||
+8
|
||||
-11
|
||||
-40
|
||||
-29
|
||||
-30
|
||||
-12
|
||||
+18
|
||||
-15
|
||||
-5
|
||||
-14
|
||||
+10
|
||||
-16
|
||||
+1
|
||||
-34
|
||||
-13
|
||||
-20
|
||||
-7
|
||||
+12
|
||||
+9
|
||||
+16
|
||||
-2
|
||||
-2
|
||||
+9
|
||||
+23
|
||||
+15
|
||||
-8
|
||||
-38
|
||||
-37
|
||||
-8
|
||||
-20
|
||||
+11
|
||||
-24
|
||||
-2
|
||||
+14
|
||||
-24
|
||||
-18
|
||||
+2
|
||||
-7
|
||||
+14
|
||||
+1
|
||||
+19
|
||||
-5
|
||||
-23
|
||||
-11
|
||||
-15
|
||||
+23
|
||||
+8
|
||||
-14
|
||||
+16
|
||||
-25
|
||||
-19
|
||||
+8
|
||||
-3
|
||||
-20
|
||||
+11
|
||||
-15
|
||||
-11
|
||||
-14
|
||||
+16
|
||||
-31
|
||||
+18
|
||||
+25
|
||||
+20
|
||||
-6
|
||||
+11
|
||||
+48
|
||||
-7
|
||||
-18
|
||||
-2
|
||||
-31
|
||||
+21
|
||||
-49
|
||||
+50
|
||||
-20
|
||||
-44
|
||||
+8
|
||||
-81
|
||||
+24
|
||||
-16
|
||||
-18
|
||||
+26
|
||||
-60
|
||||
+19
|
||||
-36
|
||||
-14
|
||||
-41
|
||||
+25
|
||||
-72
|
||||
-46
|
||||
+1
|
||||
-46
|
||||
-61361
|
||||
+12
|
||||
-18
|
||||
-7
|
||||
-9
|
||||
+6
|
||||
+14
|
||||
-13
|
||||
-8
|
||||
+19
|
||||
+19
|
||||
+11
|
||||
+9
|
||||
+2
|
||||
+9
|
||||
-18
|
||||
-3
|
||||
+20
|
||||
-4
|
||||
-11
|
||||
+4
|
||||
+14
|
||||
+3
|
||||
-11
|
||||
+2
|
||||
+2
|
||||
-13
|
||||
-17
|
||||
+3
|
||||
+19
|
||||
-13
|
||||
-16
|
||||
+11
|
||||
+14
|
||||
-5
|
||||
+12
|
||||
+16
|
||||
+17
|
||||
+15
|
||||
+6
|
||||
+6
|
||||
+2
|
||||
-1
|
||||
+15
|
||||
+6
|
||||
-3
|
||||
-5
|
||||
-6
|
||||
+20
|
||||
+16
|
||||
+7
|
||||
+1
|
||||
-5
|
||||
+9
|
||||
+12
|
||||
-2
|
||||
+11
|
||||
-16
|
||||
+6
|
||||
-14
|
||||
-3
|
||||
-11
|
||||
-8
|
||||
-18
|
||||
-9
|
||||
+2
|
||||
+12
|
||||
-15
|
||||
+20
|
||||
+1
|
||||
+1
|
||||
+10
|
||||
+5
|
||||
+17
|
||||
+7
|
||||
-2
|
||||
-14
|
||||
+1
|
||||
+10
|
||||
-1
|
||||
+12
|
||||
+12
|
||||
-37
|
||||
-13
|
||||
-3
|
||||
+5
|
||||
+3
|
||||
+18
|
||||
-14
|
||||
-26
|
||||
+11
|
||||
-14
|
||||
-3
|
||||
-14
|
||||
-6
|
||||
-21
|
||||
+2
|
||||
-8
|
||||
-3
|
||||
+18
|
||||
-3
|
||||
+18
|
||||
-10
|
||||
-15
|
||||
-6
|
||||
+10
|
||||
+5
|
||||
+17
|
||||
+14
|
||||
-16
|
||||
-10
|
||||
+6
|
||||
-2
|
||||
-1
|
||||
-6
|
||||
-12
|
||||
+14
|
||||
-5
|
||||
-11
|
||||
-11
|
||||
+7
|
||||
-6
|
||||
+9
|
||||
+20
|
||||
-11
|
||||
-21
|
||||
+14
|
||||
-7
|
||||
-8
|
||||
-29
|
||||
-12
|
||||
-2
|
||||
-3
|
||||
-17
|
||||
+9
|
||||
-7
|
||||
+13
|
||||
+18
|
||||
-9
|
||||
-11
|
||||
+12
|
||||
+11
|
||||
-1
|
||||
-24
|
||||
-7
|
||||
-14
|
||||
-13
|
||||
-18
|
||||
+9
|
||||
-16
|
||||
+19
|
||||
+18
|
||||
+16
|
||||
+2
|
||||
-13
|
||||
-19
|
||||
+7
|
||||
-19
|
||||
-1
|
||||
-8
|
||||
-16
|
||||
+2
|
||||
+15
|
||||
-16
|
||||
+18
|
||||
+13
|
||||
-19
|
||||
-3
|
||||
-2
|
||||
-4
|
||||
-14
|
||||
+9
|
||||
+10
|
||||
-14
|
||||
-15
|
||||
+6
|
||||
+8
|
||||
-12
|
||||
-11
|
||||
-3
|
||||
-12
|
||||
-4
|
||||
-18
|
||||
+14
|
||||
-13
|
||||
-10
|
||||
-14
|
||||
+15
|
||||
+3
|
||||
-15
|
||||
+2
|
||||
+1
|
||||
-9
|
||||
-11
|
||||
-1
|
||||
-17
|
||||
+16
|
||||
-5
|
||||
-2
|
||||
+19
|
||||
-8
|
||||
-19
|
||||
-3
|
||||
-19
|
||||
+12
|
||||
-17
|
||||
+6
|
||||
+16
|
||||
+19
|
||||
+4
|
||||
-5
|
||||
-4
|
||||
-11
|
||||
+13
|
||||
+15
|
||||
+7
|
||||
-11
|
||||
+16
|
||||
+4
|
||||
-1
|
||||
+18
|
||||
-15
|
||||
+20
|
||||
-11
|
||||
+8
|
||||
-13
|
||||
+19
|
||||
+7
|
||||
+11
|
||||
+19
|
||||
-1
|
||||
-7
|
||||
-17
|
||||
-2
|
||||
-19
|
||||
-11
|
||||
+15
|
||||
-11
|
||||
-16
|
||||
+15
|
||||
-10
|
||||
+25
|
||||
-5
|
||||
+9
|
||||
+17
|
||||
-16
|
||||
+12
|
||||
+10
|
||||
+5
|
||||
-2
|
||||
-17
|
||||
+11
|
||||
+16
|
||||
-4
|
||||
-3
|
||||
-4
|
||||
-4
|
||||
-3
|
||||
-7
|
||||
+4
|
||||
-9
|
||||
-19
|
||||
+1
|
||||
-5
|
||||
+29
|
||||
+2
|
||||
+28
|
||||
+15
|
||||
+20
|
||||
-15
|
||||
-13
|
||||
+20
|
||||
+20
|
||||
+3
|
||||
-10
|
||||
-11
|
||||
+20
|
||||
+5
|
||||
+14
|
||||
+6
|
||||
-18
|
||||
-13
|
||||
+1
|
||||
+15
|
||||
+30
|
||||
-23
|
||||
+28
|
||||
-7
|
||||
-10
|
||||
-19
|
||||
-21
|
||||
+20
|
||||
-5
|
||||
+12
|
||||
-9
|
||||
-10
|
||||
-9
|
||||
-15
|
||||
-23
|
||||
-1
|
||||
+17
|
||||
-2
|
||||
-10
|
||||
-1
|
||||
-13
|
||||
+28
|
||||
+22
|
||||
-6
|
||||
-8
|
||||
+43
|
||||
+42
|
||||
-8
|
||||
+27
|
||||
+4
|
||||
-18
|
||||
+49
|
||||
+19
|
||||
-8
|
||||
+9
|
||||
-2
|
||||
-1
|
||||
+37
|
||||
-12
|
||||
-11
|
||||
+17
|
||||
+15
|
||||
-6
|
||||
+24
|
||||
+19
|
||||
+6
|
||||
-74
|
||||
+6
|
||||
+26
|
||||
-317
|
||||
+4
|
||||
-23
|
||||
-9
|
||||
-17
|
||||
-17
|
||||
+13
|
||||
-19
|
||||
+8
|
||||
+14
|
||||
-6
|
||||
-6
|
||||
+1
|
||||
+10
|
||||
+10
|
||||
-1
|
||||
+9
|
||||
-7
|
||||
+18
|
||||
-9
|
||||
-8
|
||||
-4
|
||||
+7
|
||||
+18
|
||||
-3
|
||||
-16
|
||||
+18
|
||||
-5
|
||||
+11
|
||||
+12
|
||||
-1
|
||||
+9
|
||||
+11
|
||||
-14
|
||||
-9
|
||||
+19
|
||||
+24
|
||||
+30
|
||||
-27
|
||||
+76
|
||||
-35
|
||||
-34
|
||||
-82
|
||||
+14
|
||||
-25
|
||||
-10
|
||||
-3
|
||||
-7
|
||||
-14
|
||||
+16
|
||||
-4
|
||||
-2
|
||||
-5
|
||||
-18
|
||||
+9
|
||||
-7
|
||||
-1
|
||||
+6
|
||||
-15
|
||||
+11
|
||||
+18
|
||||
-4
|
||||
+16
|
||||
-9
|
||||
+11
|
||||
-16
|
||||
-25
|
||||
-11
|
||||
+21
|
||||
+6
|
||||
+5
|
||||
-10
|
||||
+7
|
||||
+20
|
||||
+22
|
||||
-10
|
||||
+4
|
||||
-10
|
||||
-16
|
||||
-6
|
||||
-18
|
||||
-31
|
||||
-69
|
||||
-12
|
||||
-18
|
||||
-25
|
||||
-8
|
||||
+49
|
||||
+50
|
||||
-19
|
||||
+60
|
||||
-16
|
||||
-96
|
||||
+200
|
||||
+34
|
||||
-148
|
||||
-153
|
||||
-45
|
||||
-1
|
||||
-45
|
||||
-61788
|
||||
-16
|
||||
-5
|
||||
-8
|
||||
-6
|
||||
+3
|
||||
-6
|
||||
+16
|
||||
+18
|
||||
+10
|
||||
-14
|
||||
+9
|
||||
-20
|
||||
+6
|
||||
+18
|
||||
+9
|
||||
+13
|
||||
+7
|
||||
+11
|
||||
-5
|
||||
-11
|
||||
+17
|
||||
+13
|
||||
-4
|
||||
-4
|
||||
-3
|
||||
-11
|
||||
-17
|
||||
-2
|
||||
+4
|
||||
+9
|
||||
-15
|
||||
-3
|
||||
+19
|
||||
-9
|
||||
-12
|
||||
-17
|
||||
+5
|
||||
-14
|
||||
+17
|
||||
-7
|
||||
-23
|
||||
-11
|
||||
+3
|
||||
-13
|
||||
+4
|
||||
+19
|
||||
-14
|
||||
-17
|
||||
+10
|
||||
+1
|
||||
+4
|
||||
-11
|
||||
+9
|
||||
-17
|
||||
+7
|
||||
-16
|
||||
+12
|
||||
-8
|
||||
+1
|
||||
-9
|
||||
-9
|
||||
-7
|
||||
-7
|
||||
+1
|
||||
+1
|
||||
+4
|
||||
+2
|
||||
-16
|
||||
+7
|
||||
+4
|
||||
-18
|
||||
-7
|
||||
+12
|
||||
+7
|
||||
-1
|
||||
-14
|
||||
+9
|
||||
-17
|
||||
-8
|
||||
+13
|
||||
+19
|
||||
-18
|
||||
-17
|
||||
-14
|
||||
-10
|
||||
-9
|
||||
-12
|
||||
-19
|
||||
-17
|
||||
+14
|
||||
-16
|
||||
+18
|
||||
-15
|
||||
-14
|
||||
-17
|
||||
-9
|
||||
-14
|
||||
-15
|
||||
-19
|
||||
-19
|
||||
+10
|
||||
-17
|
||||
-2
|
||||
+11
|
||||
+15
|
||||
+9
|
||||
+1
|
||||
+17
|
||||
+17
|
||||
-10
|
||||
-16
|
||||
+15
|
||||
+4
|
||||
-7
|
||||
+10
|
||||
+5
|
||||
-16
|
||||
-5
|
||||
-5
|
||||
-3
|
||||
-8
|
||||
+17
|
||||
-5
|
||||
+124726
|
||||
@@ -0,0 +1,250 @@
|
||||
fonbsmjyqugrapsczckghtvdxl
|
||||
fonpsmjyquwrnpeczikghtvdxw
|
||||
fonbsmdymuwrapexzikghtvdxl
|
||||
fonwsmjyquwrapeczikghttdpl
|
||||
fonbsmjkquwrapeczjkghtvdxx
|
||||
yonbsmjyquwrapecgikghtvdxc
|
||||
donbsmjyquqrapeczikghtadxl
|
||||
monbsmjyquprgpeczikghtvdxl
|
||||
fonbsmjyquwvapecqgkghtvdxl
|
||||
fonbsmjyquwrkphczikghsvdxl
|
||||
fonbomjyeuwvapeczikghtvdxl
|
||||
fonwsmjyjuwrapoczikghtvdxl
|
||||
foybsmjyquwcapeczikghsvdxl
|
||||
fonbsmjyquwrtaeczikgptvdxl
|
||||
ponbsmpyquwjapeczikghtvdxl
|
||||
flnbcmjyquwrqpeczikghtvdxl
|
||||
fonbsmjyquwrapegzikvbtvdxl
|
||||
fonbjmjyqgwrazeczikghtvdxl
|
||||
zoabsmjyquwkapeczikghtvdxl
|
||||
fonbsmjyquwrapecziktxkvdxl
|
||||
fonbsxjyrpwrapeczikghtvdxl
|
||||
fonbsmjbquwqapeciikghtvdxl
|
||||
lonbsmjyquwraphczikghtvdul
|
||||
ftnbsmjyquwrapcczikghtxdxl
|
||||
fonbsmjyqgwrapeczikghtldxc
|
||||
fonbsmjsquwmapeyzikghtvdxl
|
||||
fonbsmjyqfwrapecziqghtgdxl
|
||||
yonbsmjyquwraveczikgftvdxl
|
||||
fovbsmjyquwrapeczikggkvdxl
|
||||
fonbsmjyquwrapezzikghbvdvl
|
||||
fonzsmxyquwrapeczukghtvdxl
|
||||
fonbemjyquwrapevzikghtvrxl
|
||||
conbsxjxquwrapeczikghtvdxl
|
||||
fonbsmjsmewrapeczikghtvdxl
|
||||
folbsmjyqhwrapqczikghtvdxl
|
||||
fonbsmjyquwrzneczikghtvdxn
|
||||
fonbsmjyquirapeczikjhtvdll
|
||||
fontsmgyquwrgpeczikghtvdxl
|
||||
fonbsmjyauwrapeczbfghtvdxl
|
||||
ftnbsmjyquwrapecpifghtvdxl
|
||||
fonvsmjyqewrapeczikghlvdxl
|
||||
fonbsljyquwrapecziklhtvdxw
|
||||
fonbbmjyquwrapeczikghvadxl
|
||||
ponbsmjyquwrspeczikghivdxl
|
||||
fonbsmjcquwrapeccikghtvuxl
|
||||
fonbsmjnquwrapetzikghtvlxl
|
||||
fonbsmjymuwrapeczieghtvdxr
|
||||
ffnbsxnyquwrapeczikghtvdxl
|
||||
fonbsmjytuwrajeczzkghtvdxl
|
||||
fonssmjyquwhapeczikghkvdxl
|
||||
fonbsajyuuwrapeczikghlvdxl
|
||||
fonbsmjyquwrapeczihghtcixl
|
||||
fohbsmjyquwrapzczirghtvdxl
|
||||
fonbsmjyquwrapecjqnghtvdxl
|
||||
fonbsmjytuhrapeczihghtvdxl
|
||||
foabumjyquwrapeczikghtvdxz
|
||||
conbsmjyqtwrapeczikggtvdxl
|
||||
fonbsmjyiqwrapeczokghtvdxl
|
||||
fondsmjypuwrapeczikghtvjxl
|
||||
fonbswjyquwrapeczikgvtydxl
|
||||
fonbsmjyqqwrapeczikkhtvdbl
|
||||
fonbsmjyquwrapemzitghtvdsl
|
||||
fonbsmjyquwrspecziegxtvdxl
|
||||
fonbsmpyquwrgpeczikghtwdxl
|
||||
fodbsmjqquwrapeczmkghtvdxl
|
||||
fonbsmjkquwrapeczikghpvdxr
|
||||
fonbsmjyquwrapeczikshzvmxl
|
||||
fznbsmjyqulrapeczikghkvdxl
|
||||
fonbsmjyquwripeczikghtbdjl
|
||||
fcnbsmjyquzrapecyikghtvdxl
|
||||
ronbxmjyquwrapeczikghgvdxl
|
||||
fonbsmuyvuwrgpeczikghtvdxl
|
||||
fonbsmjyyuwraplczikghtudxl
|
||||
poxbsmjyqewrapeczikghtvdxl
|
||||
foabsmjyquwrapecziqghtvpxl
|
||||
ponbsmjrquwrapeczikchtvdxl
|
||||
fonzzmjyquwrapeczikghtvdxs
|
||||
wonbsmjyquwghpeczikghtvdxl
|
||||
fofbsejyquwrapeczikgctvdxl
|
||||
ponbsmjyquwrayegzikghtvdxl
|
||||
fonbumjyquwripeczikghtvdxf
|
||||
fonbsmqyquwrapeczikgftvdxv
|
||||
qonbsmjyquwraplczitghtvdxl
|
||||
fmnbsajdquwrapeczikghtvdxl
|
||||
fonbsrjyquwrapempikghtvdxl
|
||||
fonbsmjyquwrapeczikgotudxw
|
||||
fonbsmtyquwrapeflikghtvdxl
|
||||
fzqbsmjyquwrapecjikghtvdxl
|
||||
fdnbsmjyquwraqeclikghtvdxl
|
||||
fvnbsijyquwrapechikghtvdxl
|
||||
fovbsmjyquwsapeczikghqvdxl
|
||||
ffjbsmjyqgwrapeczikghtvdxl
|
||||
fonbsmjyquwrapeczvkhhivdxl
|
||||
forbamjjquwrapeczikghtvdxl
|
||||
fonbwmjyquwtapeyzikghtvdxl
|
||||
fonvsmjyquwrapeczikglnvdxl
|
||||
fonnsmjyguwrapeczikghtvxxl
|
||||
fopbsmjyquwrapeczikghtvaxz
|
||||
fonbsmjyquwiapeczikrhavdxl
|
||||
fonbsujyquwrapeczikthtvdjl
|
||||
fonpsmkyeuwrapeczikghtvdxl
|
||||
fonbsmjyquwrapeczqkgttvdxk
|
||||
fonbsmjyqzwrapeczikgrtddxl
|
||||
fokbsmjiquwrapeczikgltvdxl
|
||||
fonbsmjyqbwrapeczikghttdxo
|
||||
fonbsejyquwrapeczikghbvdal
|
||||
fonblmjyquwyaveczikghtvdxl
|
||||
fonbsmjyquwlzpepzikghtvdxl
|
||||
fonbsmjyqulrapbczigghtvdxl
|
||||
fonbsmjyxuwrapecziyghtvsxl
|
||||
fonbyjjyquwrapeczikghtvdxn
|
||||
fonbhmjyquwrapeczikghtjhxl
|
||||
fonbspjykuwraieczikghtvdxl
|
||||
aonbsmjyquwwapeczikchtvdxl
|
||||
fombsmjyquwyapeczikghtvdll
|
||||
fonbsmjynuwrapeczivgbtvdxl
|
||||
xonbsmjfquwrapeczikghqvdxl
|
||||
fonbyzjyquwzapeczikghtvdxl
|
||||
fbnbsmjyquwrapeczimgvtvdxl
|
||||
qonbsmjyquwraoeczikgftvdxl
|
||||
fonbsrjyquwrapeczikghtvjxm
|
||||
fonbsmjyquwrapxjzykghtvdxl
|
||||
fonbwgjyquwrapecziklhtvdxl
|
||||
fonjcmjyouwrapeczikghtvdxl
|
||||
fonbsmjyquwrapefzisuhtvdxl
|
||||
fonbsmjyqywrspeczikghtvnxl
|
||||
qonbsmjyquwrapeczlkuhtvdxl
|
||||
fonbsmjyqlprapeczikghtvdbl
|
||||
fonbsmjzquwrapedzikfhtvdxl
|
||||
fonbsmjyquwrapeczizghtvjxq
|
||||
fonbsmxyquwrrpeczikghtvcxl
|
||||
fonpsmjyquwoapeczikghjvdxl
|
||||
fonbshkyauwrapeczikghtvdxl
|
||||
fonbsmjysuwrapeczilghpvdxl
|
||||
fovwsxjyquwrapeczikghtvdxl
|
||||
fonbsmjyquwrppecnikghmvdxl
|
||||
fonbkmjyiuwrrpeczikghtvdxl
|
||||
gonbsmjyquwrapeczikphtudxl
|
||||
foncsmjyqlwrapeczimghtvdxl
|
||||
fonbsmjhquwrtpeczikghtvdxg
|
||||
fogbsmjyquarapeczikghtvdil
|
||||
fonbsmjyquwraperzekghwvdxl
|
||||
fonbstjyquwrapeczicghtedxl
|
||||
fonbsmjoquhrapeczikgotvdxl
|
||||
fonbsmjykuwrareczikgdtvdxl
|
||||
fonbsmjyvuwrayeczivghtvdxl
|
||||
fonbzmgyquwraptczikghtvdxl
|
||||
fonbsmjyqubrapeczikgftvdxb
|
||||
fonbgmjyjuwrapeczikghtvdul
|
||||
fonbsmjzqurrapeczikghtvfxl
|
||||
fonbsmjyiuwrapeczikgstvtxl
|
||||
fpnbstjyquwrapeczikghtvdcl
|
||||
fonbpmjyquwrapeczivghtndxl
|
||||
fonbsmjyquwrapeczilgptvvxl
|
||||
fonbsmjyqdwripecbikghtvdxl
|
||||
fonbsmjytuwgapnczikghtvdxl
|
||||
fonbsejyquwrapedzikghtvdml
|
||||
fonbsojyqdwrapeczikghtgdxl
|
||||
fonbsmjykuwrayeczicghtvdxl
|
||||
foubsmtyquwrapeczikchtvdxl
|
||||
fonbqmjyqukrapeyzikghtvdxl
|
||||
fonbsmjyquwaapenzikghtvdwl
|
||||
fonbsmeyquwrapeyzixghtvdxl
|
||||
fonusmjyquhrapeczikgytvdxl
|
||||
fonbsmjyquwrapwazikqhtvdxl
|
||||
fonwsmeyquwrapeczikghhvdxl
|
||||
fonmsmjyquxrspeczikghtvdxl
|
||||
fonqsmjyqxwrapeczikghtvdml
|
||||
fonfsmjyquwrapeuzikgatvdxl
|
||||
fonvsmjyquwrapeczikgrtvdul
|
||||
fonbsmayquwrapeczikihtvdxm
|
||||
fonbsmnyquwrapecdifghtvdxl
|
||||
fonbsmjyeuwraseczikghtvdxo
|
||||
fonbvvjyquwrapeczikghtvdxi
|
||||
fonbsmjyquwrapeczbkghtorxl
|
||||
tonbsmjyqvwrapeczikghtvdcl
|
||||
fonbsmjyquwrapeczhkgbtvdkl
|
||||
fonqsmjyquwrapenzibghtvdxl
|
||||
fontsmeyqudrapeczikghtvdxl
|
||||
qonbsmjyauwrapeczikghtvdbl
|
||||
fynbsmjyluwrapeczekghtvdxl
|
||||
fonbsmjhquwrappczikghtvdxt
|
||||
conbsmjyquwrapeczikahtvdxz
|
||||
fonbsmjyquorapeczikvftvdxl
|
||||
fonbsriyquwrapeczikchtvdxl
|
||||
yonfsmjyquwrapeczikghtvdxq
|
||||
fonaomjyquwrapecziwghtvdxl
|
||||
fonbsxsyqdwrapeczikghtvdxl
|
||||
fonbsqjyouwrapeczikgltvdxl
|
||||
fonbstsyquwraleczikghtvdxl
|
||||
fonbsmjyquwraoecztkghtvdsl
|
||||
fonbsmjyquwrapezzjkghmvdxl
|
||||
fonbwmjyqnwrapecpikghtvdxl
|
||||
fonbsmvyqbwrapeczikghtvdsl
|
||||
fonbsijyquwrazeczikghtvdwl
|
||||
fonbsmjyouwrapewzikghtldxl
|
||||
xonbsmjyqcwrapeczikghtvdul
|
||||
fonbgmjxquwrajeczikghtvdxl
|
||||
fokbsmjyquwrapechikghtrdxl
|
||||
fonbqmjyqawrapeczikghtrdxl
|
||||
fonbwmjzquwtapeyzikghtvdxl
|
||||
fonbsmjyquwrapecdikgatvdnl
|
||||
fonbsmjyqowrkpeczikghtvdxj
|
||||
fonbsmjyquwkapejzikuhtvdxl
|
||||
fonbsmjyquwrabeozikghtmdxl
|
||||
fonbsijyeuwrapeczikghtvdxh
|
||||
fonbsmjhquprapeczizghtvdxl
|
||||
fonesmjyquwrapcczikghtvdxh
|
||||
fonbamjyquwrapeczifrhtvdxl
|
||||
foabsmjyquwpapeczikghtvdxs
|
||||
fonbsmjyquwrapeczukghivdxh
|
||||
fonbsejyoulrapeczikghtvdxl
|
||||
fonbsmjyquwraceczikgdmvdxl
|
||||
eonbsmjyquerppeczikghtvdxl
|
||||
ffnzsmjyquwgapeczikghtvdxl
|
||||
donbsmyyquwrapeczirghtvdxl
|
||||
fjnbsmjyqufrapeczikghtwdxl
|
||||
fonfsmjyquwrareczigghtvdxl
|
||||
fonusmjyquwrapeczikgetvexl
|
||||
tonbsmjyqpwrapeczikghtjdxl
|
||||
fonbsmjhqukkapeczikghtvdxl
|
||||
fonbsmjyqusraseczikghtvzxl
|
||||
fonbsmjyquygapeczxkghtvdxl
|
||||
folbsmjyquwraqeczikghjvdxl
|
||||
fonbsmjyquwrppecjinghtvdxl
|
||||
fonbsmjyquwraepczhkghtvdxl
|
||||
fonbfmjyquwrapeczisghtrdxl
|
||||
fsnbsmjwqubrapeczikghtvdxl
|
||||
fonbspjyquwrapjczikghtedxl
|
||||
fowbsmjyquwrapeczikghtbdbl
|
||||
fonbymjyquwrapeczikghlvdrl
|
||||
fonbsmjyruwrapecbikghtvixl
|
||||
fonyqmjyqufrapeczikghtvdxl
|
||||
focbscjyquwrapeczmkghtvdxl
|
||||
fonbsmjyqtwnkpeczikghtvdxl
|
||||
eonbsmjyquwrameczizghtvdxl
|
||||
zonbsmjyqcwrapeczikghtvhxl
|
||||
foubsmjyquwrapehzikghtvnxl
|
||||
ffnbsmjyquwrapetzikghtjdxl
|
||||
fonbjgjyquwrapkczikghtvdxl
|
||||
fonbwmjyquwqapeczdkghtvdxl
|
||||
forbsmjyquwrapeczikkhtvdml
|
||||
fonbsmjyiuwrapeczivghevdxl
|
||||
fonbsmjyquwrapeglikghwvdxl
|
||||
fopgsmjyquwrapegzikghtvdxl
|
||||
fonbsmjyqzwrajeczikghtldxl
|
||||
fonbsmjyruwrapexzmkghtvdxl
|
||||
fonbsmjyquwrdpeczikxstvdxl
|
||||
fonbsmjyquwrapeezivghtvdql
|
||||
fonbdmjyqujsapeczikghtvdxl
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,976 @@
|
||||
[1518-03-31 00:26] falls asleep
|
||||
[1518-04-03 00:38] wakes up
|
||||
[1518-11-21 00:14] falls asleep
|
||||
[1518-07-21 00:34] wakes up
|
||||
[1518-04-02 00:20] falls asleep
|
||||
[1518-08-26 00:14] wakes up
|
||||
[1518-05-22 00:45] wakes up
|
||||
[1518-08-18 00:57] wakes up
|
||||
[1518-05-20 00:02] falls asleep
|
||||
[1518-07-06 00:57] falls asleep
|
||||
[1518-07-04 00:49] falls asleep
|
||||
[1518-10-23 23:49] Guard #659 begins shift
|
||||
[1518-08-06 00:07] falls asleep
|
||||
[1518-06-24 00:58] wakes up
|
||||
[1518-04-27 00:13] falls asleep
|
||||
[1518-06-08 00:01] Guard #179 begins shift
|
||||
[1518-06-03 00:00] Guard #659 begins shift
|
||||
[1518-10-03 00:35] wakes up
|
||||
[1518-04-30 00:20] wakes up
|
||||
[1518-10-15 23:59] Guard #1699 begins shift
|
||||
[1518-06-07 00:39] wakes up
|
||||
[1518-09-25 00:10] falls asleep
|
||||
[1518-09-27 00:30] falls asleep
|
||||
[1518-11-03 00:36] falls asleep
|
||||
[1518-06-26 00:55] wakes up
|
||||
[1518-04-14 00:57] wakes up
|
||||
[1518-08-07 00:45] falls asleep
|
||||
[1518-06-02 00:56] wakes up
|
||||
[1518-05-13 00:02] Guard #223 begins shift
|
||||
[1518-04-20 00:45] falls asleep
|
||||
[1518-11-14 23:59] Guard #1069 begins shift
|
||||
[1518-09-17 00:58] wakes up
|
||||
[1518-04-07 00:34] wakes up
|
||||
[1518-09-27 00:00] Guard #419 begins shift
|
||||
[1518-03-21 00:59] wakes up
|
||||
[1518-07-26 00:01] Guard #457 begins shift
|
||||
[1518-08-18 00:04] Guard #659 begins shift
|
||||
[1518-04-20 00:01] Guard #659 begins shift
|
||||
[1518-04-17 23:57] Guard #3547 begins shift
|
||||
[1518-07-10 23:59] Guard #2753 begins shift
|
||||
[1518-06-28 00:59] wakes up
|
||||
[1518-10-26 00:01] Guard #3547 begins shift
|
||||
[1518-04-15 00:49] wakes up
|
||||
[1518-09-14 00:04] Guard #179 begins shift
|
||||
[1518-07-21 00:02] falls asleep
|
||||
[1518-07-23 00:38] falls asleep
|
||||
[1518-04-04 23:59] Guard #223 begins shift
|
||||
[1518-09-15 00:12] falls asleep
|
||||
[1518-06-01 00:32] wakes up
|
||||
[1518-08-15 00:22] falls asleep
|
||||
[1518-10-05 00:34] wakes up
|
||||
[1518-10-01 00:58] wakes up
|
||||
[1518-05-05 00:07] falls asleep
|
||||
[1518-10-23 00:34] wakes up
|
||||
[1518-10-08 00:39] falls asleep
|
||||
[1518-08-27 00:14] falls asleep
|
||||
[1518-05-17 00:53] wakes up
|
||||
[1518-08-08 00:39] falls asleep
|
||||
[1518-07-28 00:03] falls asleep
|
||||
[1518-05-03 00:08] falls asleep
|
||||
[1518-10-12 00:52] falls asleep
|
||||
[1518-04-20 00:58] wakes up
|
||||
[1518-04-27 00:20] wakes up
|
||||
[1518-05-14 23:58] Guard #1933 begins shift
|
||||
[1518-07-12 23:59] Guard #2953 begins shift
|
||||
[1518-10-12 00:00] Guard #223 begins shift
|
||||
[1518-10-21 00:38] falls asleep
|
||||
[1518-04-12 00:40] falls asleep
|
||||
[1518-04-05 00:58] wakes up
|
||||
[1518-08-16 00:34] falls asleep
|
||||
[1518-07-30 23:58] Guard #419 begins shift
|
||||
[1518-10-17 00:55] wakes up
|
||||
[1518-08-06 23:59] Guard #409 begins shift
|
||||
[1518-06-17 00:47] falls asleep
|
||||
[1518-06-29 00:46] falls asleep
|
||||
[1518-09-30 00:58] wakes up
|
||||
[1518-06-29 00:53] wakes up
|
||||
[1518-03-30 00:03] Guard #457 begins shift
|
||||
[1518-11-07 00:22] falls asleep
|
||||
[1518-05-04 23:56] Guard #2953 begins shift
|
||||
[1518-09-23 00:19] wakes up
|
||||
[1518-10-12 00:16] falls asleep
|
||||
[1518-08-08 00:00] Guard #659 begins shift
|
||||
[1518-11-15 00:31] wakes up
|
||||
[1518-08-16 00:58] wakes up
|
||||
[1518-08-18 23:59] Guard #3347 begins shift
|
||||
[1518-07-06 23:58] Guard #2039 begins shift
|
||||
[1518-10-15 00:52] falls asleep
|
||||
[1518-09-18 00:36] wakes up
|
||||
[1518-06-17 23:57] Guard #409 begins shift
|
||||
[1518-09-19 23:56] Guard #647 begins shift
|
||||
[1518-10-10 00:30] wakes up
|
||||
[1518-11-18 23:58] Guard #2953 begins shift
|
||||
[1518-10-27 00:19] falls asleep
|
||||
[1518-08-05 00:51] wakes up
|
||||
[1518-07-15 23:58] Guard #1699 begins shift
|
||||
[1518-10-14 00:02] Guard #647 begins shift
|
||||
[1518-06-04 00:00] Guard #1153 begins shift
|
||||
[1518-04-16 00:00] Guard #1933 begins shift
|
||||
[1518-06-25 00:28] falls asleep
|
||||
[1518-05-13 23:57] Guard #419 begins shift
|
||||
[1518-07-09 23:58] Guard #503 begins shift
|
||||
[1518-05-08 00:16] falls asleep
|
||||
[1518-08-12 00:10] falls asleep
|
||||
[1518-09-16 00:47] falls asleep
|
||||
[1518-07-06 00:04] Guard #3547 begins shift
|
||||
[1518-06-08 00:22] falls asleep
|
||||
[1518-07-09 00:02] Guard #2953 begins shift
|
||||
[1518-08-22 23:58] Guard #179 begins shift
|
||||
[1518-05-11 00:51] wakes up
|
||||
[1518-06-05 00:59] wakes up
|
||||
[1518-10-03 00:25] wakes up
|
||||
[1518-05-05 00:17] wakes up
|
||||
[1518-11-10 23:58] Guard #457 begins shift
|
||||
[1518-09-17 00:04] Guard #409 begins shift
|
||||
[1518-08-17 00:02] falls asleep
|
||||
[1518-08-13 00:32] falls asleep
|
||||
[1518-09-02 00:00] Guard #419 begins shift
|
||||
[1518-07-24 00:48] falls asleep
|
||||
[1518-04-10 00:32] wakes up
|
||||
[1518-04-20 00:42] wakes up
|
||||
[1518-03-24 00:03] Guard #223 begins shift
|
||||
[1518-11-21 23:50] Guard #2953 begins shift
|
||||
[1518-09-20 00:57] wakes up
|
||||
[1518-08-11 00:42] wakes up
|
||||
[1518-08-08 00:49] wakes up
|
||||
[1518-06-12 23:47] Guard #647 begins shift
|
||||
[1518-03-26 00:58] wakes up
|
||||
[1518-11-02 00:55] wakes up
|
||||
[1518-10-22 00:03] Guard #1069 begins shift
|
||||
[1518-07-14 23:59] Guard #401 begins shift
|
||||
[1518-04-30 00:15] falls asleep
|
||||
[1518-06-21 00:37] wakes up
|
||||
[1518-07-15 00:54] wakes up
|
||||
[1518-05-14 00:50] wakes up
|
||||
[1518-09-16 00:53] wakes up
|
||||
[1518-09-05 00:01] Guard #2039 begins shift
|
||||
[1518-05-25 23:59] Guard #2753 begins shift
|
||||
[1518-10-28 00:30] falls asleep
|
||||
[1518-10-06 23:56] Guard #2953 begins shift
|
||||
[1518-08-21 00:01] Guard #419 begins shift
|
||||
[1518-04-25 23:59] Guard #2693 begins shift
|
||||
[1518-11-16 00:55] wakes up
|
||||
[1518-05-12 00:47] wakes up
|
||||
[1518-07-03 00:39] falls asleep
|
||||
[1518-05-10 00:54] falls asleep
|
||||
[1518-03-30 00:57] wakes up
|
||||
[1518-11-20 00:56] falls asleep
|
||||
[1518-07-23 00:11] wakes up
|
||||
[1518-10-12 00:59] wakes up
|
||||
[1518-04-25 00:03] Guard #1153 begins shift
|
||||
[1518-11-05 23:57] Guard #179 begins shift
|
||||
[1518-03-30 23:53] Guard #691 begins shift
|
||||
[1518-05-15 23:57] Guard #223 begins shift
|
||||
[1518-08-23 00:31] falls asleep
|
||||
[1518-08-22 00:54] wakes up
|
||||
[1518-09-07 00:53] falls asleep
|
||||
[1518-11-20 00:00] Guard #1699 begins shift
|
||||
[1518-08-13 00:35] wakes up
|
||||
[1518-09-15 00:59] wakes up
|
||||
[1518-10-27 00:42] wakes up
|
||||
[1518-05-27 00:22] wakes up
|
||||
[1518-08-18 00:25] wakes up
|
||||
[1518-08-04 00:28] falls asleep
|
||||
[1518-09-24 00:57] wakes up
|
||||
[1518-07-24 00:57] wakes up
|
||||
[1518-07-16 00:51] wakes up
|
||||
[1518-05-25 00:37] falls asleep
|
||||
[1518-06-01 00:14] falls asleep
|
||||
[1518-10-05 00:20] falls asleep
|
||||
[1518-04-15 00:11] wakes up
|
||||
[1518-05-23 23:56] Guard #2953 begins shift
|
||||
[1518-11-22 00:04] falls asleep
|
||||
[1518-09-11 00:59] wakes up
|
||||
[1518-10-23 00:44] wakes up
|
||||
[1518-11-13 00:41] falls asleep
|
||||
[1518-10-06 00:04] Guard #2753 begins shift
|
||||
[1518-04-25 00:48] wakes up
|
||||
[1518-05-01 00:13] falls asleep
|
||||
[1518-06-27 00:49] wakes up
|
||||
[1518-09-29 00:18] falls asleep
|
||||
[1518-10-02 23:56] Guard #691 begins shift
|
||||
[1518-03-28 00:42] wakes up
|
||||
[1518-05-30 00:23] falls asleep
|
||||
[1518-10-21 00:24] falls asleep
|
||||
[1518-11-03 00:28] wakes up
|
||||
[1518-10-18 00:20] falls asleep
|
||||
[1518-10-11 00:45] falls asleep
|
||||
[1518-10-02 00:23] falls asleep
|
||||
[1518-11-02 00:42] wakes up
|
||||
[1518-11-03 00:01] Guard #457 begins shift
|
||||
[1518-08-05 00:47] falls asleep
|
||||
[1518-09-05 00:23] wakes up
|
||||
[1518-08-28 00:00] Guard #1069 begins shift
|
||||
[1518-09-17 00:44] wakes up
|
||||
[1518-06-16 23:59] Guard #691 begins shift
|
||||
[1518-08-05 00:02] Guard #1069 begins shift
|
||||
[1518-04-12 00:01] Guard #691 begins shift
|
||||
[1518-11-06 00:43] wakes up
|
||||
[1518-06-09 00:28] falls asleep
|
||||
[1518-05-14 00:26] falls asleep
|
||||
[1518-09-11 00:04] Guard #2693 begins shift
|
||||
[1518-09-06 00:33] falls asleep
|
||||
[1518-09-29 00:44] wakes up
|
||||
[1518-06-04 23:49] Guard #1933 begins shift
|
||||
[1518-03-25 00:02] Guard #1153 begins shift
|
||||
[1518-10-25 00:59] wakes up
|
||||
[1518-08-29 00:37] falls asleep
|
||||
[1518-09-30 00:40] wakes up
|
||||
[1518-05-17 23:50] Guard #223 begins shift
|
||||
[1518-05-19 23:46] Guard #1933 begins shift
|
||||
[1518-07-18 00:40] falls asleep
|
||||
[1518-09-23 00:33] falls asleep
|
||||
[1518-09-08 00:17] falls asleep
|
||||
[1518-11-19 00:12] falls asleep
|
||||
[1518-03-31 00:05] falls asleep
|
||||
[1518-08-24 00:31] wakes up
|
||||
[1518-05-11 00:10] falls asleep
|
||||
[1518-07-29 00:14] wakes up
|
||||
[1518-07-10 00:43] wakes up
|
||||
[1518-08-18 00:15] falls asleep
|
||||
[1518-04-10 00:50] wakes up
|
||||
[1518-05-26 00:23] wakes up
|
||||
[1518-09-03 00:04] Guard #223 begins shift
|
||||
[1518-04-11 00:06] falls asleep
|
||||
[1518-07-29 00:12] falls asleep
|
||||
[1518-10-04 00:28] wakes up
|
||||
[1518-08-21 00:49] falls asleep
|
||||
[1518-10-15 00:43] wakes up
|
||||
[1518-03-26 00:47] wakes up
|
||||
[1518-04-08 00:58] wakes up
|
||||
[1518-07-27 00:52] wakes up
|
||||
[1518-05-30 23:56] Guard #179 begins shift
|
||||
[1518-09-22 00:02] Guard #2693 begins shift
|
||||
[1518-10-14 00:46] falls asleep
|
||||
[1518-11-05 00:21] falls asleep
|
||||
[1518-05-16 23:59] Guard #1069 begins shift
|
||||
[1518-05-17 00:27] falls asleep
|
||||
[1518-09-28 00:52] falls asleep
|
||||
[1518-07-22 00:20] falls asleep
|
||||
[1518-06-13 00:02] falls asleep
|
||||
[1518-05-28 00:27] falls asleep
|
||||
[1518-05-07 00:43] wakes up
|
||||
[1518-05-20 00:44] falls asleep
|
||||
[1518-05-20 23:57] Guard #691 begins shift
|
||||
[1518-05-02 00:51] wakes up
|
||||
[1518-10-01 00:53] falls asleep
|
||||
[1518-11-04 00:26] falls asleep
|
||||
[1518-04-01 00:55] wakes up
|
||||
[1518-04-07 00:25] falls asleep
|
||||
[1518-03-26 00:03] Guard #1933 begins shift
|
||||
[1518-07-16 00:28] falls asleep
|
||||
[1518-07-05 00:03] Guard #163 begins shift
|
||||
[1518-04-24 00:49] wakes up
|
||||
[1518-03-30 00:23] falls asleep
|
||||
[1518-04-27 00:04] Guard #647 begins shift
|
||||
[1518-07-31 00:36] falls asleep
|
||||
[1518-10-06 00:42] wakes up
|
||||
[1518-06-10 00:51] wakes up
|
||||
[1518-08-10 00:22] falls asleep
|
||||
[1518-04-22 00:00] Guard #647 begins shift
|
||||
[1518-04-16 00:43] wakes up
|
||||
[1518-05-27 00:13] falls asleep
|
||||
[1518-07-18 23:58] Guard #2039 begins shift
|
||||
[1518-05-11 00:37] falls asleep
|
||||
[1518-09-28 00:34] wakes up
|
||||
[1518-08-26 00:49] wakes up
|
||||
[1518-04-26 00:24] falls asleep
|
||||
[1518-07-04 00:50] wakes up
|
||||
[1518-05-15 00:57] wakes up
|
||||
[1518-11-01 00:39] wakes up
|
||||
[1518-09-28 00:55] wakes up
|
||||
[1518-06-25 00:17] wakes up
|
||||
[1518-06-25 00:00] Guard #163 begins shift
|
||||
[1518-07-20 00:59] wakes up
|
||||
[1518-10-06 00:36] falls asleep
|
||||
[1518-10-02 00:02] Guard #659 begins shift
|
||||
[1518-09-23 23:50] Guard #503 begins shift
|
||||
[1518-03-20 00:00] Guard #457 begins shift
|
||||
[1518-04-24 00:19] falls asleep
|
||||
[1518-05-08 00:51] wakes up
|
||||
[1518-07-16 23:58] Guard #2753 begins shift
|
||||
[1518-11-01 00:49] wakes up
|
||||
[1518-11-08 00:00] Guard #1699 begins shift
|
||||
[1518-06-12 00:15] falls asleep
|
||||
[1518-10-18 23:59] Guard #647 begins shift
|
||||
[1518-08-02 00:53] wakes up
|
||||
[1518-05-23 00:29] wakes up
|
||||
[1518-03-25 00:09] falls asleep
|
||||
[1518-10-21 00:25] wakes up
|
||||
[1518-03-22 00:00] Guard #503 begins shift
|
||||
[1518-05-19 00:05] falls asleep
|
||||
[1518-06-09 00:50] wakes up
|
||||
[1518-09-26 00:32] wakes up
|
||||
[1518-03-24 00:34] falls asleep
|
||||
[1518-08-25 00:01] Guard #1069 begins shift
|
||||
[1518-04-26 00:44] wakes up
|
||||
[1518-05-22 00:00] Guard #419 begins shift
|
||||
[1518-11-20 00:57] wakes up
|
||||
[1518-05-02 00:50] falls asleep
|
||||
[1518-11-17 00:41] wakes up
|
||||
[1518-06-07 00:21] falls asleep
|
||||
[1518-06-19 00:24] falls asleep
|
||||
[1518-08-08 23:57] Guard #1069 begins shift
|
||||
[1518-11-16 00:36] falls asleep
|
||||
[1518-09-03 00:45] wakes up
|
||||
[1518-07-15 00:44] wakes up
|
||||
[1518-07-11 00:25] wakes up
|
||||
[1518-09-18 23:51] Guard #2953 begins shift
|
||||
[1518-10-03 23:49] Guard #1933 begins shift
|
||||
[1518-10-30 00:31] falls asleep
|
||||
[1518-09-18 00:33] falls asleep
|
||||
[1518-08-10 00:39] wakes up
|
||||
[1518-07-30 00:56] wakes up
|
||||
[1518-09-25 23:51] Guard #659 begins shift
|
||||
[1518-11-19 00:59] wakes up
|
||||
[1518-05-21 00:55] wakes up
|
||||
[1518-10-15 00:53] wakes up
|
||||
[1518-09-22 00:20] falls asleep
|
||||
[1518-04-21 00:44] falls asleep
|
||||
[1518-11-12 00:45] wakes up
|
||||
[1518-05-23 00:28] falls asleep
|
||||
[1518-05-05 23:59] Guard #2753 begins shift
|
||||
[1518-10-15 00:39] falls asleep
|
||||
[1518-09-09 00:51] wakes up
|
||||
[1518-06-11 23:57] Guard #1069 begins shift
|
||||
[1518-06-01 00:47] wakes up
|
||||
[1518-09-28 00:43] falls asleep
|
||||
[1518-04-27 00:33] falls asleep
|
||||
[1518-08-08 00:31] wakes up
|
||||
[1518-09-09 23:59] Guard #691 begins shift
|
||||
[1518-10-17 00:43] wakes up
|
||||
[1518-10-23 00:43] falls asleep
|
||||
[1518-07-03 00:50] wakes up
|
||||
[1518-07-06 00:33] wakes up
|
||||
[1518-06-25 00:41] wakes up
|
||||
[1518-06-13 00:44] wakes up
|
||||
[1518-10-28 00:35] wakes up
|
||||
[1518-08-16 00:01] falls asleep
|
||||
[1518-03-22 00:17] falls asleep
|
||||
[1518-07-06 00:47] wakes up
|
||||
[1518-09-13 00:01] Guard #659 begins shift
|
||||
[1518-06-14 00:01] Guard #2953 begins shift
|
||||
[1518-07-19 00:57] wakes up
|
||||
[1518-09-15 23:58] Guard #223 begins shift
|
||||
[1518-10-19 00:06] falls asleep
|
||||
[1518-09-21 00:49] wakes up
|
||||
[1518-08-26 00:03] falls asleep
|
||||
[1518-07-08 00:13] falls asleep
|
||||
[1518-06-08 23:56] Guard #1069 begins shift
|
||||
[1518-07-27 00:37] falls asleep
|
||||
[1518-07-06 00:17] falls asleep
|
||||
[1518-04-23 00:25] wakes up
|
||||
[1518-06-30 00:33] wakes up
|
||||
[1518-04-08 00:46] falls asleep
|
||||
[1518-04-02 00:57] wakes up
|
||||
[1518-11-22 00:51] falls asleep
|
||||
[1518-06-10 23:58] Guard #1933 begins shift
|
||||
[1518-09-15 00:49] falls asleep
|
||||
[1518-10-10 00:42] falls asleep
|
||||
[1518-04-14 00:49] falls asleep
|
||||
[1518-09-03 23:59] Guard #2039 begins shift
|
||||
[1518-06-17 00:34] falls asleep
|
||||
[1518-07-20 00:00] Guard #2953 begins shift
|
||||
[1518-07-31 00:41] wakes up
|
||||
[1518-10-25 00:45] falls asleep
|
||||
[1518-03-24 00:30] wakes up
|
||||
[1518-04-10 00:15] falls asleep
|
||||
[1518-06-30 00:36] falls asleep
|
||||
[1518-07-03 00:01] Guard #2953 begins shift
|
||||
[1518-05-21 00:08] falls asleep
|
||||
[1518-09-04 00:29] wakes up
|
||||
[1518-10-03 00:10] falls asleep
|
||||
[1518-06-04 00:56] wakes up
|
||||
[1518-09-04 00:23] falls asleep
|
||||
[1518-05-09 23:59] Guard #179 begins shift
|
||||
[1518-10-20 00:42] wakes up
|
||||
[1518-07-22 00:04] Guard #1699 begins shift
|
||||
[1518-06-23 00:49] wakes up
|
||||
[1518-04-29 00:58] wakes up
|
||||
[1518-05-02 00:03] Guard #647 begins shift
|
||||
[1518-08-03 00:07] falls asleep
|
||||
[1518-09-24 00:22] falls asleep
|
||||
[1518-04-13 00:05] falls asleep
|
||||
[1518-09-03 00:41] falls asleep
|
||||
[1518-09-26 00:00] falls asleep
|
||||
[1518-05-10 00:45] wakes up
|
||||
[1518-04-18 00:39] wakes up
|
||||
[1518-11-15 00:41] falls asleep
|
||||
[1518-05-25 00:04] Guard #409 begins shift
|
||||
[1518-07-07 00:35] falls asleep
|
||||
[1518-04-28 00:53] wakes up
|
||||
[1518-11-21 00:54] wakes up
|
||||
[1518-10-10 00:24] falls asleep
|
||||
[1518-07-17 00:40] falls asleep
|
||||
[1518-10-26 00:18] falls asleep
|
||||
[1518-07-14 00:58] wakes up
|
||||
[1518-06-27 00:11] falls asleep
|
||||
[1518-09-17 00:51] falls asleep
|
||||
[1518-07-25 00:51] wakes up
|
||||
[1518-07-02 00:06] falls asleep
|
||||
[1518-03-29 00:01] falls asleep
|
||||
[1518-11-09 00:57] wakes up
|
||||
[1518-08-06 00:32] wakes up
|
||||
[1518-10-02 00:25] wakes up
|
||||
[1518-08-17 00:39] wakes up
|
||||
[1518-06-21 00:21] falls asleep
|
||||
[1518-11-17 23:53] Guard #3547 begins shift
|
||||
[1518-04-17 00:38] wakes up
|
||||
[1518-04-12 00:50] wakes up
|
||||
[1518-11-23 00:49] wakes up
|
||||
[1518-10-05 00:07] falls asleep
|
||||
[1518-03-20 00:14] falls asleep
|
||||
[1518-05-28 00:00] Guard #1933 begins shift
|
||||
[1518-05-29 00:04] falls asleep
|
||||
[1518-10-28 00:43] falls asleep
|
||||
[1518-03-26 00:21] falls asleep
|
||||
[1518-11-21 00:50] falls asleep
|
||||
[1518-10-04 00:05] falls asleep
|
||||
[1518-05-07 00:19] falls asleep
|
||||
[1518-10-10 00:50] falls asleep
|
||||
[1518-03-31 00:45] wakes up
|
||||
[1518-10-06 00:30] falls asleep
|
||||
[1518-11-04 00:00] Guard #179 begins shift
|
||||
[1518-05-28 00:56] falls asleep
|
||||
[1518-05-18 00:31] falls asleep
|
||||
[1518-09-08 00:34] falls asleep
|
||||
[1518-09-13 00:17] falls asleep
|
||||
[1518-03-19 00:37] falls asleep
|
||||
[1518-06-30 00:58] wakes up
|
||||
[1518-03-23 00:23] falls asleep
|
||||
[1518-07-30 00:26] falls asleep
|
||||
[1518-04-09 00:47] wakes up
|
||||
[1518-07-26 00:11] falls asleep
|
||||
[1518-07-02 00:04] Guard #1699 begins shift
|
||||
[1518-09-14 00:51] wakes up
|
||||
[1518-04-29 00:46] falls asleep
|
||||
[1518-04-19 00:58] wakes up
|
||||
[1518-04-18 00:57] wakes up
|
||||
[1518-07-14 00:10] falls asleep
|
||||
[1518-05-28 00:33] wakes up
|
||||
[1518-05-10 00:27] falls asleep
|
||||
[1518-09-28 00:18] falls asleep
|
||||
[1518-08-13 00:01] Guard #647 begins shift
|
||||
[1518-09-06 00:51] wakes up
|
||||
[1518-11-17 00:02] Guard #2953 begins shift
|
||||
[1518-04-09 00:31] falls asleep
|
||||
[1518-07-08 00:02] Guard #659 begins shift
|
||||
[1518-09-22 00:58] wakes up
|
||||
[1518-07-28 00:34] wakes up
|
||||
[1518-11-17 00:22] falls asleep
|
||||
[1518-04-03 00:00] Guard #659 begins shift
|
||||
[1518-08-14 00:51] wakes up
|
||||
[1518-05-12 00:04] Guard #2039 begins shift
|
||||
[1518-09-16 00:39] wakes up
|
||||
[1518-06-02 00:19] falls asleep
|
||||
[1518-08-19 23:58] Guard #3547 begins shift
|
||||
[1518-04-21 00:03] Guard #179 begins shift
|
||||
[1518-04-17 00:13] falls asleep
|
||||
[1518-06-26 23:56] Guard #1933 begins shift
|
||||
[1518-03-27 23:58] Guard #2693 begins shift
|
||||
[1518-04-01 00:11] falls asleep
|
||||
[1518-08-30 00:04] Guard #2753 begins shift
|
||||
[1518-11-02 00:16] wakes up
|
||||
[1518-10-08 00:01] Guard #2039 begins shift
|
||||
[1518-04-02 00:00] Guard #457 begins shift
|
||||
[1518-10-04 00:55] wakes up
|
||||
[1518-05-28 00:58] wakes up
|
||||
[1518-09-13 00:55] wakes up
|
||||
[1518-08-23 00:38] wakes up
|
||||
[1518-04-18 00:25] wakes up
|
||||
[1518-08-15 23:51] Guard #401 begins shift
|
||||
[1518-07-28 00:48] wakes up
|
||||
[1518-08-27 00:02] Guard #691 begins shift
|
||||
[1518-03-28 00:59] wakes up
|
||||
[1518-08-29 00:04] Guard #1153 begins shift
|
||||
[1518-07-31 23:58] Guard #3347 begins shift
|
||||
[1518-11-01 23:56] Guard #409 begins shift
|
||||
[1518-08-12 00:32] falls asleep
|
||||
[1518-06-05 00:05] falls asleep
|
||||
[1518-09-16 00:21] falls asleep
|
||||
[1518-04-04 00:03] Guard #1637 begins shift
|
||||
[1518-04-12 00:26] wakes up
|
||||
[1518-06-15 00:23] wakes up
|
||||
[1518-05-07 00:01] Guard #1699 begins shift
|
||||
[1518-05-06 00:43] falls asleep
|
||||
[1518-09-27 00:46] wakes up
|
||||
[1518-07-22 00:58] wakes up
|
||||
[1518-09-03 00:36] falls asleep
|
||||
[1518-04-16 23:58] Guard #419 begins shift
|
||||
[1518-11-11 00:20] falls asleep
|
||||
[1518-04-20 00:11] falls asleep
|
||||
[1518-06-29 00:27] falls asleep
|
||||
[1518-10-09 00:59] wakes up
|
||||
[1518-07-15 00:31] falls asleep
|
||||
[1518-11-10 00:00] Guard #419 begins shift
|
||||
[1518-09-11 00:40] falls asleep
|
||||
[1518-03-24 00:59] wakes up
|
||||
[1518-06-01 00:36] falls asleep
|
||||
[1518-05-31 00:33] falls asleep
|
||||
[1518-05-16 00:47] falls asleep
|
||||
[1518-10-12 00:40] falls asleep
|
||||
[1518-10-23 00:29] falls asleep
|
||||
[1518-11-22 00:37] wakes up
|
||||
[1518-07-09 00:54] wakes up
|
||||
[1518-07-05 00:42] falls asleep
|
||||
[1518-07-29 00:00] Guard #2953 begins shift
|
||||
[1518-09-30 00:46] falls asleep
|
||||
[1518-08-10 00:03] Guard #2039 begins shift
|
||||
[1518-03-27 00:08] falls asleep
|
||||
[1518-03-24 00:24] falls asleep
|
||||
[1518-05-09 00:25] falls asleep
|
||||
[1518-06-14 00:57] wakes up
|
||||
[1518-10-29 23:56] Guard #1699 begins shift
|
||||
[1518-05-02 23:56] Guard #401 begins shift
|
||||
[1518-11-20 00:27] falls asleep
|
||||
[1518-07-20 23:51] Guard #419 begins shift
|
||||
[1518-04-06 00:59] wakes up
|
||||
[1518-10-01 00:04] Guard #2753 begins shift
|
||||
[1518-10-01 00:46] wakes up
|
||||
[1518-07-14 00:02] Guard #1069 begins shift
|
||||
[1518-04-16 00:25] falls asleep
|
||||
[1518-10-10 23:56] Guard #691 begins shift
|
||||
[1518-08-20 00:58] wakes up
|
||||
[1518-09-21 00:11] falls asleep
|
||||
[1518-04-03 00:26] falls asleep
|
||||
[1518-06-20 00:54] wakes up
|
||||
[1518-11-01 00:04] Guard #1069 begins shift
|
||||
[1518-05-28 23:54] Guard #2039 begins shift
|
||||
[1518-03-22 00:36] wakes up
|
||||
[1518-10-26 00:40] wakes up
|
||||
[1518-10-11 00:51] wakes up
|
||||
[1518-04-27 00:58] wakes up
|
||||
[1518-04-10 00:18] wakes up
|
||||
[1518-04-22 00:54] wakes up
|
||||
[1518-09-12 00:48] wakes up
|
||||
[1518-04-28 00:23] falls asleep
|
||||
[1518-11-21 00:38] wakes up
|
||||
[1518-05-20 00:40] wakes up
|
||||
[1518-10-14 00:51] wakes up
|
||||
[1518-06-27 00:46] falls asleep
|
||||
[1518-09-18 00:44] falls asleep
|
||||
[1518-10-09 23:56] Guard #419 begins shift
|
||||
[1518-04-27 00:18] falls asleep
|
||||
[1518-10-20 00:59] wakes up
|
||||
[1518-05-17 00:47] falls asleep
|
||||
[1518-04-18 00:08] falls asleep
|
||||
[1518-07-29 00:58] wakes up
|
||||
[1518-06-10 00:03] Guard #1699 begins shift
|
||||
[1518-09-06 00:15] falls asleep
|
||||
[1518-10-23 00:49] wakes up
|
||||
[1518-11-12 00:33] falls asleep
|
||||
[1518-10-12 23:51] Guard #163 begins shift
|
||||
[1518-06-04 00:33] falls asleep
|
||||
[1518-08-24 00:43] falls asleep
|
||||
[1518-07-17 23:56] Guard #1699 begins shift
|
||||
[1518-10-02 00:44] wakes up
|
||||
[1518-09-12 00:01] Guard #401 begins shift
|
||||
[1518-08-12 00:28] wakes up
|
||||
[1518-07-18 00:27] wakes up
|
||||
[1518-03-27 00:01] Guard #647 begins shift
|
||||
[1518-05-27 00:57] wakes up
|
||||
[1518-03-20 00:26] wakes up
|
||||
[1518-04-23 00:01] Guard #691 begins shift
|
||||
[1518-09-24 23:59] Guard #1153 begins shift
|
||||
[1518-06-02 00:34] wakes up
|
||||
[1518-09-09 00:02] Guard #503 begins shift
|
||||
[1518-04-11 00:03] Guard #457 begins shift
|
||||
[1518-05-30 00:38] wakes up
|
||||
[1518-04-05 00:43] falls asleep
|
||||
[1518-06-17 00:59] wakes up
|
||||
[1518-05-01 00:04] Guard #659 begins shift
|
||||
[1518-06-11 00:46] wakes up
|
||||
[1518-09-12 00:08] falls asleep
|
||||
[1518-08-18 00:41] falls asleep
|
||||
[1518-07-19 00:36] wakes up
|
||||
[1518-09-02 00:39] wakes up
|
||||
[1518-05-27 00:50] falls asleep
|
||||
[1518-10-13 00:54] wakes up
|
||||
[1518-07-09 00:17] falls asleep
|
||||
[1518-07-05 00:26] falls asleep
|
||||
[1518-08-10 23:50] Guard #659 begins shift
|
||||
[1518-04-27 00:14] wakes up
|
||||
[1518-04-29 00:42] wakes up
|
||||
[1518-11-09 00:50] falls asleep
|
||||
[1518-05-24 00:39] falls asleep
|
||||
[1518-09-15 00:45] wakes up
|
||||
[1518-07-06 00:58] wakes up
|
||||
[1518-09-09 00:56] falls asleep
|
||||
[1518-09-20 23:59] Guard #2039 begins shift
|
||||
[1518-06-24 00:47] falls asleep
|
||||
[1518-07-03 00:56] falls asleep
|
||||
[1518-06-01 23:59] Guard #223 begins shift
|
||||
[1518-04-13 00:35] wakes up
|
||||
[1518-05-07 23:57] Guard #457 begins shift
|
||||
[1518-11-08 00:43] wakes up
|
||||
[1518-07-27 00:03] Guard #1153 begins shift
|
||||
[1518-08-07 00:53] wakes up
|
||||
[1518-09-20 00:33] wakes up
|
||||
[1518-11-14 00:44] wakes up
|
||||
[1518-05-31 00:44] wakes up
|
||||
[1518-06-22 00:44] wakes up
|
||||
[1518-05-15 00:15] falls asleep
|
||||
[1518-09-30 00:00] Guard #2693 begins shift
|
||||
[1518-11-22 00:53] wakes up
|
||||
[1518-10-20 23:58] Guard #163 begins shift
|
||||
[1518-06-15 23:56] Guard #1699 begins shift
|
||||
[1518-07-08 00:34] wakes up
|
||||
[1518-11-02 00:30] falls asleep
|
||||
[1518-06-03 00:57] wakes up
|
||||
[1518-06-30 00:15] falls asleep
|
||||
[1518-04-12 00:54] falls asleep
|
||||
[1518-06-19 00:00] Guard #1933 begins shift
|
||||
[1518-11-11 23:57] Guard #179 begins shift
|
||||
[1518-04-08 00:02] Guard #503 begins shift
|
||||
[1518-04-09 23:57] Guard #163 begins shift
|
||||
[1518-07-21 00:50] falls asleep
|
||||
[1518-11-12 00:10] falls asleep
|
||||
[1518-10-10 00:54] wakes up
|
||||
[1518-10-27 23:59] Guard #1069 begins shift
|
||||
[1518-08-03 00:59] wakes up
|
||||
[1518-07-23 23:58] Guard #223 begins shift
|
||||
[1518-08-21 00:59] wakes up
|
||||
[1518-05-09 00:43] wakes up
|
||||
[1518-06-26 00:16] falls asleep
|
||||
[1518-08-21 00:50] wakes up
|
||||
[1518-10-16 00:35] falls asleep
|
||||
[1518-09-28 00:49] wakes up
|
||||
[1518-05-30 00:00] Guard #419 begins shift
|
||||
[1518-11-12 00:13] wakes up
|
||||
[1518-06-07 00:53] falls asleep
|
||||
[1518-07-18 00:58] wakes up
|
||||
[1518-07-10 00:54] falls asleep
|
||||
[1518-09-07 00:55] wakes up
|
||||
[1518-04-19 00:57] falls asleep
|
||||
[1518-05-05 00:52] wakes up
|
||||
[1518-06-18 00:55] wakes up
|
||||
[1518-10-18 00:00] Guard #1933 begins shift
|
||||
[1518-09-11 00:23] wakes up
|
||||
[1518-06-22 23:58] Guard #2953 begins shift
|
||||
[1518-06-29 00:42] wakes up
|
||||
[1518-04-10 00:25] falls asleep
|
||||
[1518-11-13 00:00] Guard #2753 begins shift
|
||||
[1518-03-28 23:50] Guard #419 begins shift
|
||||
[1518-08-25 00:39] wakes up
|
||||
[1518-08-21 00:57] falls asleep
|
||||
[1518-08-29 00:49] wakes up
|
||||
[1518-10-12 00:48] wakes up
|
||||
[1518-05-11 00:23] wakes up
|
||||
[1518-06-23 23:56] Guard #1153 begins shift
|
||||
[1518-05-19 00:50] wakes up
|
||||
[1518-11-13 00:55] wakes up
|
||||
[1518-07-05 00:28] wakes up
|
||||
[1518-10-18 00:53] wakes up
|
||||
[1518-07-19 00:54] falls asleep
|
||||
[1518-06-07 00:42] falls asleep
|
||||
[1518-10-22 00:47] wakes up
|
||||
[1518-05-03 00:54] falls asleep
|
||||
[1518-09-05 00:17] falls asleep
|
||||
[1518-10-21 00:42] wakes up
|
||||
[1518-11-01 00:13] falls asleep
|
||||
[1518-05-10 23:58] Guard #223 begins shift
|
||||
[1518-07-01 00:48] wakes up
|
||||
[1518-03-23 00:55] wakes up
|
||||
[1518-08-16 23:54] Guard #2039 begins shift
|
||||
[1518-04-29 00:16] falls asleep
|
||||
[1518-07-01 00:20] falls asleep
|
||||
[1518-05-03 00:57] wakes up
|
||||
[1518-06-28 00:03] Guard #179 begins shift
|
||||
[1518-04-25 00:21] falls asleep
|
||||
[1518-05-13 00:38] wakes up
|
||||
[1518-05-18 23:52] Guard #1699 begins shift
|
||||
[1518-04-14 23:59] Guard #2039 begins shift
|
||||
[1518-06-28 00:51] falls asleep
|
||||
[1518-07-20 00:20] falls asleep
|
||||
[1518-06-02 00:42] falls asleep
|
||||
[1518-09-08 00:04] Guard #1699 begins shift
|
||||
[1518-05-18 00:01] falls asleep
|
||||
[1518-11-10 00:48] wakes up
|
||||
[1518-10-08 23:56] Guard #409 begins shift
|
||||
[1518-10-19 00:53] wakes up
|
||||
[1518-04-12 00:55] wakes up
|
||||
[1518-06-23 00:14] falls asleep
|
||||
[1518-09-02 00:17] falls asleep
|
||||
[1518-09-20 00:20] falls asleep
|
||||
[1518-11-18 00:03] falls asleep
|
||||
[1518-09-23 00:12] falls asleep
|
||||
[1518-06-20 00:08] falls asleep
|
||||
[1518-09-29 00:05] falls asleep
|
||||
[1518-08-20 00:16] falls asleep
|
||||
[1518-10-05 00:16] wakes up
|
||||
[1518-09-04 00:55] wakes up
|
||||
[1518-10-05 00:00] Guard #3547 begins shift
|
||||
[1518-10-29 00:11] falls asleep
|
||||
[1518-09-03 00:37] wakes up
|
||||
[1518-06-07 00:01] Guard #457 begins shift
|
||||
[1518-10-16 00:54] wakes up
|
||||
[1518-05-20 00:34] falls asleep
|
||||
[1518-06-01 00:01] Guard #1069 begins shift
|
||||
[1518-08-11 00:04] falls asleep
|
||||
[1518-03-27 00:12] wakes up
|
||||
[1518-11-07 00:55] wakes up
|
||||
[1518-08-22 00:00] falls asleep
|
||||
[1518-08-30 00:51] wakes up
|
||||
[1518-07-11 00:21] falls asleep
|
||||
[1518-07-21 00:53] wakes up
|
||||
[1518-10-02 00:30] falls asleep
|
||||
[1518-10-06 00:31] wakes up
|
||||
[1518-07-26 00:45] wakes up
|
||||
[1518-11-21 00:00] Guard #2693 begins shift
|
||||
[1518-03-21 00:03] Guard #691 begins shift
|
||||
[1518-06-21 00:00] Guard #503 begins shift
|
||||
[1518-07-10 00:08] falls asleep
|
||||
[1518-07-23 00:09] falls asleep
|
||||
[1518-09-05 00:29] falls asleep
|
||||
[1518-09-10 00:23] falls asleep
|
||||
[1518-06-20 00:04] Guard #1933 begins shift
|
||||
[1518-06-30 23:59] Guard #691 begins shift
|
||||
[1518-10-09 00:35] falls asleep
|
||||
[1518-10-19 23:58] Guard #179 begins shift
|
||||
[1518-09-06 00:18] wakes up
|
||||
[1518-04-10 00:47] falls asleep
|
||||
[1518-08-28 00:18] falls asleep
|
||||
[1518-05-18 00:06] wakes up
|
||||
[1518-11-06 00:31] wakes up
|
||||
[1518-08-08 00:26] falls asleep
|
||||
[1518-11-08 00:30] falls asleep
|
||||
[1518-09-20 00:56] falls asleep
|
||||
[1518-08-15 00:42] wakes up
|
||||
[1518-09-18 00:50] wakes up
|
||||
[1518-06-03 00:22] falls asleep
|
||||
[1518-05-25 00:56] wakes up
|
||||
[1518-06-11 00:33] falls asleep
|
||||
[1518-05-16 00:59] wakes up
|
||||
[1518-09-18 00:03] Guard #659 begins shift
|
||||
[1518-10-30 00:48] wakes up
|
||||
[1518-08-26 00:25] falls asleep
|
||||
[1518-11-15 00:26] falls asleep
|
||||
[1518-06-19 00:26] wakes up
|
||||
[1518-10-29 00:42] wakes up
|
||||
[1518-09-01 00:47] wakes up
|
||||
[1518-08-25 23:48] Guard #1069 begins shift
|
||||
[1518-06-22 00:32] falls asleep
|
||||
[1518-08-21 23:51] Guard #1069 begins shift
|
||||
[1518-10-12 00:22] wakes up
|
||||
[1518-10-27 00:26] wakes up
|
||||
[1518-04-28 23:58] Guard #179 begins shift
|
||||
[1518-06-10 00:58] wakes up
|
||||
[1518-11-06 00:18] falls asleep
|
||||
[1518-07-20 00:57] falls asleep
|
||||
[1518-04-01 00:35] falls asleep
|
||||
[1518-08-14 00:10] falls asleep
|
||||
[1518-06-06 00:52] wakes up
|
||||
[1518-08-27 00:33] wakes up
|
||||
[1518-07-04 00:00] Guard #691 begins shift
|
||||
[1518-07-25 00:33] falls asleep
|
||||
[1518-11-10 00:21] falls asleep
|
||||
[1518-08-16 00:17] wakes up
|
||||
[1518-11-05 00:51] wakes up
|
||||
[1518-10-01 00:41] falls asleep
|
||||
[1518-04-08 00:20] wakes up
|
||||
[1518-08-12 00:00] Guard #223 begins shift
|
||||
[1518-09-01 00:03] Guard #223 begins shift
|
||||
[1518-10-28 00:54] wakes up
|
||||
[1518-09-12 00:45] falls asleep
|
||||
[1518-11-01 00:44] falls asleep
|
||||
[1518-03-19 00:02] Guard #2953 begins shift
|
||||
[1518-04-06 00:41] falls asleep
|
||||
[1518-07-15 00:49] falls asleep
|
||||
[1518-10-25 00:16] falls asleep
|
||||
[1518-05-28 00:46] falls asleep
|
||||
[1518-03-27 00:22] falls asleep
|
||||
[1518-10-17 00:50] falls asleep
|
||||
[1518-04-13 23:57] Guard #1153 begins shift
|
||||
[1518-09-04 00:37] falls asleep
|
||||
[1518-05-01 00:57] wakes up
|
||||
[1518-11-13 23:57] Guard #691 begins shift
|
||||
[1518-03-21 00:31] falls asleep
|
||||
[1518-10-10 00:45] wakes up
|
||||
[1518-04-28 00:09] falls asleep
|
||||
[1518-06-07 00:57] wakes up
|
||||
[1518-07-28 00:47] falls asleep
|
||||
[1518-09-06 23:58] Guard #409 begins shift
|
||||
[1518-06-13 00:53] wakes up
|
||||
[1518-10-03 00:33] falls asleep
|
||||
[1518-06-16 00:34] wakes up
|
||||
[1518-03-28 00:18] falls asleep
|
||||
[1518-10-07 00:26] falls asleep
|
||||
[1518-10-23 00:00] Guard #1069 begins shift
|
||||
[1518-06-18 00:20] falls asleep
|
||||
[1518-11-09 00:04] Guard #457 begins shift
|
||||
[1518-11-03 00:59] wakes up
|
||||
[1518-11-09 00:25] falls asleep
|
||||
[1518-04-15 00:08] falls asleep
|
||||
[1518-05-03 00:35] wakes up
|
||||
[1518-04-28 00:12] wakes up
|
||||
[1518-04-06 00:03] Guard #179 begins shift
|
||||
[1518-07-20 00:44] wakes up
|
||||
[1518-09-05 00:48] wakes up
|
||||
[1518-06-17 00:35] wakes up
|
||||
[1518-07-24 23:57] Guard #223 begins shift
|
||||
[1518-10-29 00:00] Guard #419 begins shift
|
||||
[1518-03-19 00:41] wakes up
|
||||
[1518-07-30 00:00] Guard #2953 begins shift
|
||||
[1518-06-14 00:50] falls asleep
|
||||
[1518-07-12 00:32] wakes up
|
||||
[1518-06-25 23:57] Guard #1069 begins shift
|
||||
[1518-06-10 00:44] falls asleep
|
||||
[1518-05-17 00:32] wakes up
|
||||
[1518-10-08 00:48] wakes up
|
||||
[1518-11-03 00:22] falls asleep
|
||||
[1518-10-24 00:02] falls asleep
|
||||
[1518-10-27 00:29] falls asleep
|
||||
[1518-04-01 00:23] wakes up
|
||||
[1518-08-05 00:33] wakes up
|
||||
[1518-08-09 00:41] wakes up
|
||||
[1518-11-06 00:42] falls asleep
|
||||
[1518-08-24 00:49] wakes up
|
||||
[1518-09-14 23:56] Guard #1699 begins shift
|
||||
[1518-07-19 00:11] falls asleep
|
||||
[1518-04-15 00:37] falls asleep
|
||||
[1518-09-01 00:34] falls asleep
|
||||
[1518-07-29 00:22] falls asleep
|
||||
[1518-11-02 00:51] falls asleep
|
||||
[1518-05-02 00:22] wakes up
|
||||
[1518-05-26 00:10] falls asleep
|
||||
[1518-10-24 23:59] Guard #1153 begins shift
|
||||
[1518-07-12 00:01] Guard #691 begins shift
|
||||
[1518-08-04 00:04] Guard #691 begins shift
|
||||
[1518-05-02 00:58] wakes up
|
||||
[1518-11-11 00:52] wakes up
|
||||
[1518-10-31 00:00] Guard #683 begins shift
|
||||
[1518-06-13 00:50] falls asleep
|
||||
[1518-07-05 00:53] wakes up
|
||||
[1518-07-05 00:22] wakes up
|
||||
[1518-10-23 00:48] falls asleep
|
||||
[1518-04-22 00:52] falls asleep
|
||||
[1518-09-28 00:04] Guard #647 begins shift
|
||||
[1518-05-04 00:24] falls asleep
|
||||
[1518-05-20 00:21] wakes up
|
||||
[1518-10-15 00:01] Guard #409 begins shift
|
||||
[1518-09-10 00:33] wakes up
|
||||
[1518-04-28 00:01] Guard #1699 begins shift
|
||||
[1518-04-11 00:50] wakes up
|
||||
[1518-05-05 00:23] falls asleep
|
||||
[1518-10-16 23:59] Guard #409 begins shift
|
||||
[1518-11-15 00:51] wakes up
|
||||
[1518-09-09 00:33] falls asleep
|
||||
[1518-07-12 00:21] falls asleep
|
||||
[1518-04-12 23:51] Guard #1699 begins shift
|
||||
[1518-06-10 00:54] falls asleep
|
||||
[1518-07-13 00:39] wakes up
|
||||
[1518-09-12 00:38] wakes up
|
||||
[1518-06-06 00:02] Guard #1153 begins shift
|
||||
[1518-06-25 00:10] falls asleep
|
||||
[1518-09-24 00:14] wakes up
|
||||
[1518-10-24 00:33] wakes up
|
||||
[1518-07-17 00:43] wakes up
|
||||
[1518-07-23 00:03] Guard #419 begins shift
|
||||
[1518-10-07 00:55] wakes up
|
||||
[1518-05-04 00:04] Guard #2753 begins shift
|
||||
[1518-05-22 00:06] falls asleep
|
||||
[1518-10-13 00:04] falls asleep
|
||||
[1518-11-23 00:02] Guard #457 begins shift
|
||||
[1518-08-04 00:57] wakes up
|
||||
[1518-09-30 00:33] falls asleep
|
||||
[1518-11-02 00:15] falls asleep
|
||||
[1518-03-28 00:56] falls asleep
|
||||
[1518-10-04 00:47] falls asleep
|
||||
[1518-04-30 00:03] Guard #401 begins shift
|
||||
[1518-06-27 00:33] wakes up
|
||||
[1518-07-10 00:56] wakes up
|
||||
[1518-03-25 00:51] wakes up
|
||||
[1518-10-20 00:33] falls asleep
|
||||
[1518-11-20 00:51] wakes up
|
||||
[1518-05-06 00:46] wakes up
|
||||
[1518-07-27 23:47] Guard #3547 begins shift
|
||||
[1518-08-02 00:02] Guard #419 begins shift
|
||||
[1518-08-12 00:55] wakes up
|
||||
[1518-09-22 23:58] Guard #419 begins shift
|
||||
[1518-05-27 00:03] Guard #457 begins shift
|
||||
[1518-04-08 00:19] falls asleep
|
||||
[1518-07-27 00:20] falls asleep
|
||||
[1518-03-31 00:22] wakes up
|
||||
[1518-09-29 00:14] wakes up
|
||||
[1518-06-07 00:50] wakes up
|
||||
[1518-07-05 00:06] falls asleep
|
||||
[1518-09-14 00:06] falls asleep
|
||||
[1518-05-20 00:54] wakes up
|
||||
[1518-08-15 00:51] falls asleep
|
||||
[1518-04-18 00:44] falls asleep
|
||||
[1518-07-27 00:24] wakes up
|
||||
[1518-10-20 00:52] falls asleep
|
||||
[1518-08-28 00:45] wakes up
|
||||
[1518-08-02 00:15] falls asleep
|
||||
[1518-04-21 00:52] wakes up
|
||||
[1518-07-23 00:51] wakes up
|
||||
[1518-09-19 00:02] falls asleep
|
||||
[1518-10-26 23:59] Guard #179 begins shift
|
||||
[1518-04-23 00:15] falls asleep
|
||||
[1518-04-06 23:57] Guard #2693 begins shift
|
||||
[1518-09-23 00:38] wakes up
|
||||
[1518-08-05 00:28] falls asleep
|
||||
[1518-09-08 00:51] wakes up
|
||||
[1518-11-09 00:44] wakes up
|
||||
[1518-07-03 00:59] wakes up
|
||||
[1518-08-06 00:00] Guard #419 begins shift
|
||||
[1518-06-16 00:29] falls asleep
|
||||
[1518-09-28 23:53] Guard #401 begins shift
|
||||
[1518-11-04 23:57] Guard #163 begins shift
|
||||
[1518-07-31 00:19] wakes up
|
||||
[1518-06-06 00:43] falls asleep
|
||||
[1518-11-04 00:42] wakes up
|
||||
[1518-08-02 23:59] Guard #1699 begins shift
|
||||
[1518-05-10 00:56] wakes up
|
||||
[1518-05-28 00:48] wakes up
|
||||
[1518-08-09 00:13] falls asleep
|
||||
[1518-06-22 00:04] Guard #2953 begins shift
|
||||
[1518-05-08 23:59] Guard #2953 begins shift
|
||||
[1518-04-01 00:03] Guard #419 begins shift
|
||||
[1518-10-25 00:38] wakes up
|
||||
[1518-05-02 00:13] falls asleep
|
||||
[1518-05-04 00:51] wakes up
|
||||
[1518-10-17 00:41] falls asleep
|
||||
[1518-09-24 00:03] falls asleep
|
||||
[1518-09-09 00:58] wakes up
|
||||
[1518-04-12 00:12] falls asleep
|
||||
[1518-06-14 23:48] Guard #2693 begins shift
|
||||
[1518-03-27 00:35] wakes up
|
||||
[1518-03-23 00:02] Guard #223 begins shift
|
||||
[1518-06-12 00:50] wakes up
|
||||
[1518-07-18 00:23] falls asleep
|
||||
[1518-08-25 00:30] falls asleep
|
||||
[1518-05-12 00:11] falls asleep
|
||||
[1518-09-19 00:40] wakes up
|
||||
[1518-08-15 00:57] wakes up
|
||||
[1518-09-25 00:46] wakes up
|
||||
[1518-07-07 00:41] wakes up
|
||||
[1518-05-02 00:54] falls asleep
|
||||
[1518-05-24 00:57] wakes up
|
||||
[1518-11-16 00:00] Guard #2039 begins shift
|
||||
[1518-08-24 00:23] falls asleep
|
||||
[1518-07-13 00:36] falls asleep
|
||||
[1518-07-02 00:42] falls asleep
|
||||
[1518-04-08 23:57] Guard #2953 begins shift
|
||||
[1518-06-29 23:56] Guard #3547 begins shift
|
||||
[1518-03-26 00:56] falls asleep
|
||||
[1518-08-15 00:01] Guard #659 begins shift
|
||||
[1518-06-29 00:00] Guard #1153 begins shift
|
||||
[1518-05-29 00:56] wakes up
|
||||
[1518-05-13 00:07] falls asleep
|
||||
[1518-04-24 00:01] Guard #419 begins shift
|
||||
[1518-09-17 00:40] falls asleep
|
||||
[1518-08-23 23:59] Guard #179 begins shift
|
||||
[1518-08-31 00:04] Guard #1637 begins shift
|
||||
[1518-10-22 00:14] falls asleep
|
||||
[1518-04-19 00:04] Guard #3547 begins shift
|
||||
[1518-06-15 00:01] falls asleep
|
||||
[1518-06-08 00:46] wakes up
|
||||
[1518-08-14 00:03] Guard #2693 begins shift
|
||||
[1518-07-06 00:44] falls asleep
|
||||
[1518-11-14 00:27] falls asleep
|
||||
[1518-09-08 00:18] wakes up
|
||||
[1518-07-02 00:45] wakes up
|
||||
[1518-05-22 23:59] Guard #1699 begins shift
|
||||
[1518-07-02 00:37] wakes up
|
||||
[1518-07-31 00:16] falls asleep
|
||||
[1518-08-30 00:12] falls asleep
|
||||
[1518-09-06 00:01] Guard #409 begins shift
|
||||
[1518-11-06 23:57] Guard #223 begins shift
|
||||
[1518-11-23 00:24] falls asleep
|
||||
[1518-04-18 00:36] falls asleep
|
||||
[1518-11-18 00:16] wakes up
|
||||
[1518-05-18 00:51] wakes up
|
||||
[1518-03-29 00:48] wakes up
|
||||
[1518-09-11 00:16] falls asleep
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,101 @@
|
||||
Step G must be finished before step X can begin.
|
||||
Step X must be finished before step B can begin.
|
||||
Step A must be finished before step I can begin.
|
||||
Step D must be finished before step H can begin.
|
||||
Step O must be finished before step T can begin.
|
||||
Step H must be finished before step C can begin.
|
||||
Step S must be finished before step E can begin.
|
||||
Step U must be finished before step M can begin.
|
||||
Step M must be finished before step Z can begin.
|
||||
Step R must be finished before step N can begin.
|
||||
Step C must be finished before step Q can begin.
|
||||
Step T must be finished before step P can begin.
|
||||
Step I must be finished before step W can begin.
|
||||
Step W must be finished before step N can begin.
|
||||
Step P must be finished before step J can begin.
|
||||
Step N must be finished before step F can begin.
|
||||
Step Y must be finished before step J can begin.
|
||||
Step J must be finished before step L can begin.
|
||||
Step L must be finished before step E can begin.
|
||||
Step E must be finished before step B can begin.
|
||||
Step Q must be finished before step B can begin.
|
||||
Step F must be finished before step K can begin.
|
||||
Step V must be finished before step K can begin.
|
||||
Step Z must be finished before step B can begin.
|
||||
Step B must be finished before step K can begin.
|
||||
Step G must be finished before step U can begin.
|
||||
Step E must be finished before step V can begin.
|
||||
Step A must be finished before step Z can begin.
|
||||
Step C must be finished before step V can begin.
|
||||
Step R must be finished before step B can begin.
|
||||
Step Q must be finished before step Z can begin.
|
||||
Step R must be finished before step K can begin.
|
||||
Step T must be finished before step B can begin.
|
||||
Step L must be finished before step B can begin.
|
||||
Step M must be finished before step K can begin.
|
||||
Step T must be finished before step Z can begin.
|
||||
Step W must be finished before step B can begin.
|
||||
Step I must be finished before step E can begin.
|
||||
Step A must be finished before step M can begin.
|
||||
Step V must be finished before step Z can begin.
|
||||
Step Y must be finished before step B can begin.
|
||||
Step Q must be finished before step F can begin.
|
||||
Step W must be finished before step Y can begin.
|
||||
Step U must be finished before step K can begin.
|
||||
Step D must be finished before step F can begin.
|
||||
Step P must be finished before step F can begin.
|
||||
Step N must be finished before step L can begin.
|
||||
Step H must be finished before step T can begin.
|
||||
Step H must be finished before step L can begin.
|
||||
Step C must be finished before step T can begin.
|
||||
Step H must be finished before step I can begin.
|
||||
Step Z must be finished before step K can begin.
|
||||
Step L must be finished before step Z can begin.
|
||||
Step Y must be finished before step K can begin.
|
||||
Step I must be finished before step V can begin.
|
||||
Step P must be finished before step K can begin.
|
||||
Step P must be finished before step N can begin.
|
||||
Step G must be finished before step D can begin.
|
||||
Step I must be finished before step J can begin.
|
||||
Step H must be finished before step K can begin.
|
||||
Step L must be finished before step Q can begin.
|
||||
Step D must be finished before step M can begin.
|
||||
Step O must be finished before step V can begin.
|
||||
Step R must be finished before step L can begin.
|
||||
Step D must be finished before step W can begin.
|
||||
Step M must be finished before step J can begin.
|
||||
Step O must be finished before step R can begin.
|
||||
Step N must be finished before step Z can begin.
|
||||
Step Y must be finished before step V can begin.
|
||||
Step W must be finished before step L can begin.
|
||||
Step U must be finished before step Y can begin.
|
||||
Step S must be finished before step V can begin.
|
||||
Step M must be finished before step P can begin.
|
||||
Step X must be finished before step A can begin.
|
||||
Step A must be finished before step E can begin.
|
||||
Step A must be finished before step L can begin.
|
||||
Step A must be finished before step R can begin.
|
||||
Step V must be finished before step B can begin.
|
||||
Step P must be finished before step B can begin.
|
||||
Step E must be finished before step F can begin.
|
||||
Step T must be finished before step V can begin.
|
||||
Step S must be finished before step R can begin.
|
||||
Step T must be finished before step F can begin.
|
||||
Step P must be finished before step Y can begin.
|
||||
Step A must be finished before step C can begin.
|
||||
Step J must be finished before step F can begin.
|
||||
Step H must be finished before step B can begin.
|
||||
Step C must be finished before step E can begin.
|
||||
Step P must be finished before step E can begin.
|
||||
Step D must be finished before step I can begin.
|
||||
Step X must be finished before step F can begin.
|
||||
Step T must be finished before step Q can begin.
|
||||
Step J must be finished before step B can begin.
|
||||
Step C must be finished before step B can begin.
|
||||
Step P must be finished before step Q can begin.
|
||||
Step H must be finished before step R can begin.
|
||||
Step F must be finished before step B can begin.
|
||||
Step T must be finished before step J can begin.
|
||||
Step A must be finished before step W can begin.
|
||||
Step N must be finished before step K can begin.
|
||||
Step T must be finished before step E can begin.
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,347 @@
|
||||
position=< 10253, -50152> velocity=<-1, 5>
|
||||
position=< 20314, 40332> velocity=<-2, -4>
|
||||
position=<-19881, -30049> velocity=< 2, 3>
|
||||
position=<-29940, 10166> velocity=< 3, -1>
|
||||
position=<-40022, -40103> velocity=< 4, 4>
|
||||
position=< 30403, 20217> velocity=<-3, -2>
|
||||
position=< 20330, 10172> velocity=<-2, -1>
|
||||
position=< 30397, -40102> velocity=<-3, 4>
|
||||
position=< 10305, -50152> velocity=<-1, 5>
|
||||
position=< 20347, 10167> velocity=<-2, -1>
|
||||
position=< 30389, 50381> velocity=<-3, -5>
|
||||
position=< 50485, -40103> velocity=<-5, 4>
|
||||
position=< -9840, 40325> velocity=< 1, -4>
|
||||
position=<-29951, 20217> velocity=< 3, -2>
|
||||
position=< 40441, -30053> velocity=<-4, 3>
|
||||
position=<-19906, 20217> velocity=< 2, -2>
|
||||
position=< 40443, -50153> velocity=<-4, 5>
|
||||
position=< 40446, -19991> velocity=<-4, 2>
|
||||
position=< 30378, 40325> velocity=<-3, -4>
|
||||
position=< 20359, 20226> velocity=<-2, -2>
|
||||
position=<-50072, -30046> velocity=< 5, 3>
|
||||
position=< 30370, 30271> velocity=<-3, -3>
|
||||
position=< -9854, 20226> velocity=< 1, -2>
|
||||
position=<-29948, 10168> velocity=< 3, -1>
|
||||
position=<-19886, 50388> velocity=< 2, -5>
|
||||
position=<-50062, 20222> velocity=< 5, -2>
|
||||
position=<-29921, 30271> velocity=< 3, -3>
|
||||
position=<-29929, 30276> velocity=< 3, -3>
|
||||
position=< 30408, -30051> velocity=<-3, 3>
|
||||
position=< 40422, -40099> velocity=<-4, 4>
|
||||
position=<-50047, -9940> velocity=< 5, 1>
|
||||
position=< 30392, -19995> velocity=<-3, 2>
|
||||
position=<-39967, -40098> velocity=< 4, 4>
|
||||
position=< 30371, 30275> velocity=<-3, -3>
|
||||
position=<-19902, -30045> velocity=< 2, 3>
|
||||
position=< 30388, 50380> velocity=<-3, -5>
|
||||
position=< 30352, 10169> velocity=<-3, -1>
|
||||
position=<-29940, 40333> velocity=< 3, -4>
|
||||
position=<-50069, 30280> velocity=< 5, -3>
|
||||
position=<-39978, 10168> velocity=< 4, -1>
|
||||
position=<-39968, -9941> velocity=< 4, 1>
|
||||
position=<-19918, -40102> velocity=< 2, 4>
|
||||
position=< 10289, -50156> velocity=<-1, 5>
|
||||
position=< 40419, -50161> velocity=<-4, 5>
|
||||
position=<-50059, -40106> velocity=< 5, 4>
|
||||
position=< 10281, -50157> velocity=<-1, 5>
|
||||
position=< 40454, 50386> velocity=<-4, -5>
|
||||
position=< 20298, -30044> velocity=<-2, 3>
|
||||
position=< -9839, -9945> velocity=< 1, 1>
|
||||
position=<-19858, 30271> velocity=< 2, -3>
|
||||
position=<-50040, 40334> velocity=< 5, -4>
|
||||
position=< -9819, -9936> velocity=< 1, 1>
|
||||
position=< 10292, -30049> velocity=<-1, 3>
|
||||
position=< 30409, 30271> velocity=<-3, -3>
|
||||
position=< 40443, 30276> velocity=<-4, -3>
|
||||
position=<-19918, -50157> velocity=< 2, 5>
|
||||
position=< 10289, 30273> velocity=<-1, -3>
|
||||
position=<-29914, 50388> velocity=< 3, -5>
|
||||
position=< 20349, 50383> velocity=<-2, -5>
|
||||
position=<-39969, -50161> velocity=< 4, 5>
|
||||
position=< 50484, -40101> velocity=<-5, 4>
|
||||
position=<-29931, 40330> velocity=< 3, -4>
|
||||
position=< 50486, -50152> velocity=<-5, 5>
|
||||
position=< 50508, 40327> velocity=<-5, -4>
|
||||
position=< 30393, -50160> velocity=<-3, 5>
|
||||
position=< 50464, -19990> velocity=<-5, 2>
|
||||
position=< 30392, 50381> velocity=<-3, -5>
|
||||
position=<-29915, -30044> velocity=< 3, 3>
|
||||
position=< 50496, 30276> velocity=<-5, -3>
|
||||
position=< 30370, 30280> velocity=<-3, -3>
|
||||
position=< 40417, 10163> velocity=<-4, -1>
|
||||
position=< 10264, 30271> velocity=<-1, -3>
|
||||
position=< 30364, 40329> velocity=<-3, -4>
|
||||
position=< -9819, -40099> velocity=< 1, 4>
|
||||
position=< -9837, -50157> velocity=< 1, 5>
|
||||
position=< 50496, -40102> velocity=<-5, 4>
|
||||
position=<-39989, 10172> velocity=< 4, -1>
|
||||
position=< 20330, -40098> velocity=<-2, 4>
|
||||
position=<-50048, 20220> velocity=< 5, -2>
|
||||
position=< 10246, 30275> velocity=<-1, -3>
|
||||
position=< 10304, 20226> velocity=<-1, -2>
|
||||
position=<-40023, 10172> velocity=< 4, -1>
|
||||
position=<-19858, -50157> velocity=< 2, 5>
|
||||
position=< 30400, 50380> velocity=<-3, -5>
|
||||
position=<-40006, 50382> velocity=< 4, -5>
|
||||
position=< 50497, 50382> velocity=<-5, -5>
|
||||
position=< 30400, 20226> velocity=<-3, -2>
|
||||
position=< -9861, -19999> velocity=< 1, 2>
|
||||
position=<-29916, 10165> velocity=< 3, -1>
|
||||
position=< 40409, 20221> velocity=<-4, -2>
|
||||
position=<-40015, 30280> velocity=< 4, -3>
|
||||
position=< 50494, -19999> velocity=<-5, 2>
|
||||
position=< 10268, 40326> velocity=<-1, -4>
|
||||
position=< -9821, 20217> velocity=< 1, -2>
|
||||
position=<-29940, -30047> velocity=< 3, 3>
|
||||
position=<-19870, 20221> velocity=< 2, -2>
|
||||
position=< 20346, 20220> velocity=<-2, -2>
|
||||
position=< 40456, -40103> velocity=<-4, 4>
|
||||
position=<-19893, 10172> velocity=< 2, -1>
|
||||
position=<-29960, -19993> velocity=< 3, 2>
|
||||
position=<-50036, 30276> velocity=< 5, -3>
|
||||
position=< -9840, -30046> velocity=< 1, 3>
|
||||
position=<-19906, 20220> velocity=< 2, -2>
|
||||
position=<-19860, 20217> velocity=< 2, -2>
|
||||
position=<-29916, -40106> velocity=< 3, 4>
|
||||
position=<-50061, -9936> velocity=< 5, 1>
|
||||
position=<-29972, 30277> velocity=< 3, -3>
|
||||
position=<-50048, -40104> velocity=< 5, 4>
|
||||
position=< 20354, 20224> velocity=<-2, -2>
|
||||
position=<-19866, 50383> velocity=< 2, -5>
|
||||
position=< -9855, 20226> velocity=< 1, -2>
|
||||
position=<-40023, -50152> velocity=< 4, 5>
|
||||
position=< 10245, -50161> velocity=<-1, 5>
|
||||
position=<-39997, -19999> velocity=< 4, 2>
|
||||
position=< -9840, -19991> velocity=< 1, 2>
|
||||
position=< 30394, 50379> velocity=<-3, -5>
|
||||
position=< 20318, -50161> velocity=<-2, 5>
|
||||
position=<-50024, 50379> velocity=< 5, -5>
|
||||
position=<-29972, -50159> velocity=< 3, 5>
|
||||
position=<-19878, 10168> velocity=< 2, -1>
|
||||
position=< 30368, 10163> velocity=<-3, -1>
|
||||
position=< 30371, 20226> velocity=<-3, -2>
|
||||
position=<-19873, 50383> velocity=< 2, -5>
|
||||
position=< 20351, 10164> velocity=<-2, -1>
|
||||
position=< 40433, -9945> velocity=<-4, 1>
|
||||
position=< 10248, 50379> velocity=<-1, -5>
|
||||
position=<-50072, -9937> velocity=< 5, 1>
|
||||
position=<-29960, -9938> velocity=< 3, 1>
|
||||
position=< 50468, -30045> velocity=<-5, 3>
|
||||
position=<-50024, 20224> velocity=< 5, -2>
|
||||
position=< 50484, -9944> velocity=<-5, 1>
|
||||
position=< 40451, 10165> velocity=<-4, -1>
|
||||
position=< 40422, -19992> velocity=<-4, 2>
|
||||
position=<-19886, 50387> velocity=< 2, -5>
|
||||
position=< 10293, -9941> velocity=<-1, 1>
|
||||
position=< 40418, -40105> velocity=<-4, 4>
|
||||
position=< 10304, 50383> velocity=<-1, -5>
|
||||
position=<-29960, 40330> velocity=< 3, -4>
|
||||
position=<-39983, 50379> velocity=< 4, -5>
|
||||
position=< 30389, -30047> velocity=<-3, 3>
|
||||
position=<-40023, 50379> velocity=< 4, -5>
|
||||
position=<-29916, 40334> velocity=< 3, -4>
|
||||
position=<-19918, 30280> velocity=< 2, -3>
|
||||
position=<-29948, 20221> velocity=< 3, -2>
|
||||
position=<-39989, -30050> velocity=< 4, 3>
|
||||
position=< 30394, -50161> velocity=<-3, 5>
|
||||
position=< -9832, 30278> velocity=< 1, -3>
|
||||
position=<-29923, 40325> velocity=< 3, -4>
|
||||
position=< 20319, -40105> velocity=<-2, 4>
|
||||
position=< 30353, 30275> velocity=<-3, -3>
|
||||
position=< -9804, -50152> velocity=< 1, 5>
|
||||
position=<-19905, -9945> velocity=< 2, 1>
|
||||
position=< -9835, -50152> velocity=< 1, 5>
|
||||
position=< 40406, 40326> velocity=<-4, -4>
|
||||
position=< 50508, 10163> velocity=<-5, -1>
|
||||
position=<-19865, 10165> velocity=< 2, -1>
|
||||
position=< 10276, -50157> velocity=<-1, 5>
|
||||
position=<-19870, -19996> velocity=< 2, 2>
|
||||
position=<-19870, 30280> velocity=< 2, -3>
|
||||
position=<-39970, 40332> velocity=< 4, -4>
|
||||
position=< 40462, 50383> velocity=<-4, -5>
|
||||
position=< 40451, 10170> velocity=<-4, -1>
|
||||
position=< 40451, 50385> velocity=<-4, -5>
|
||||
position=<-29924, 30279> velocity=< 3, -3>
|
||||
position=< 30397, 30280> velocity=<-3, -3>
|
||||
position=<-40014, 50380> velocity=< 4, -5>
|
||||
position=<-19858, 50388> velocity=< 2, -5>
|
||||
position=<-29927, 50387> velocity=< 3, -5>
|
||||
position=<-29924, 40330> velocity=< 3, -4>
|
||||
position=<-19918, -9940> velocity=< 2, 1>
|
||||
position=< 50484, -19991> velocity=<-5, 2>
|
||||
position=< 40432, -19999> velocity=<-4, 2>
|
||||
position=<-50072, -9937> velocity=< 5, 1>
|
||||
position=< 30396, -9944> velocity=<-3, 1>
|
||||
position=<-19885, -50160> velocity=< 2, 5>
|
||||
position=< 10273, -9936> velocity=<-1, 1>
|
||||
position=< 50484, -9940> velocity=<-5, 1>
|
||||
position=<-40002, 20226> velocity=< 4, -2>
|
||||
position=<-50045, -50161> velocity=< 5, 5>
|
||||
position=<-29960, 50385> velocity=< 3, -5>
|
||||
position=<-29972, 20219> velocity=< 3, -2>
|
||||
position=< -9837, -9945> velocity=< 1, 1>
|
||||
position=< 30408, -50161> velocity=<-3, 5>
|
||||
position=< 20298, -19997> velocity=<-2, 2>
|
||||
position=<-39985, 10168> velocity=< 4, -1>
|
||||
position=< 50496, 30272> velocity=<-5, -3>
|
||||
position=<-29927, -50157> velocity=< 3, 5>
|
||||
position=<-50076, 50383> velocity=< 5, -5>
|
||||
position=< 30369, -9945> velocity=<-3, 1>
|
||||
position=< 50517, 40334> velocity=<-5, -4>
|
||||
position=<-29946, 10167> velocity=< 3, -1>
|
||||
position=< 30368, -50161> velocity=<-3, 5>
|
||||
position=< 50476, 30280> velocity=<-5, -3>
|
||||
position=< 30373, -30044> velocity=<-3, 3>
|
||||
position=< 10244, 50382> velocity=<-1, -5>
|
||||
position=< 40418, 10167> velocity=<-4, -1>
|
||||
position=<-50048, 50384> velocity=< 5, -5>
|
||||
position=< 50487, -40103> velocity=<-5, 4>
|
||||
position=< -9863, -19990> velocity=< 1, 2>
|
||||
position=< -9836, 30280> velocity=< 1, -3>
|
||||
position=<-50028, -19995> velocity=< 5, 2>
|
||||
position=<-29944, -19990> velocity=< 3, 2>
|
||||
position=< 20333, -9945> velocity=<-2, 1>
|
||||
position=<-50024, 10166> velocity=< 5, -1>
|
||||
position=<-40002, -40104> velocity=< 4, 4>
|
||||
position=< 40424, -40102> velocity=<-4, 4>
|
||||
position=< 10300, -9944> velocity=<-1, 1>
|
||||
position=< -9864, 20218> velocity=< 1, -2>
|
||||
position=<-50043, 20225> velocity=< 5, -2>
|
||||
position=<-40006, -50158> velocity=< 4, 5>
|
||||
position=<-50078, 30280> velocity=< 5, -3>
|
||||
position=< 20318, 40334> velocity=<-2, -4>
|
||||
position=< 40410, -9936> velocity=<-4, 1>
|
||||
position=<-29955, -30047> velocity=< 3, 3>
|
||||
position=<-50022, 30280> velocity=< 5, -3>
|
||||
position=<-19894, 10165> velocity=< 2, -1>
|
||||
position=<-19865, 50382> velocity=< 2, -5>
|
||||
position=<-29924, 50388> velocity=< 3, -5>
|
||||
position=<-39981, 50387> velocity=< 4, -5>
|
||||
position=< 40407, 50388> velocity=<-4, -5>
|
||||
position=<-29924, -40100> velocity=< 3, 4>
|
||||
position=< -9816, -30049> velocity=< 1, 3>
|
||||
position=<-50044, 10168> velocity=< 5, -1>
|
||||
position=< 50493, 40326> velocity=<-5, -4>
|
||||
position=< 30402, -9941> velocity=<-3, 1>
|
||||
position=<-50043, 30277> velocity=< 5, -3>
|
||||
position=< 50516, 30280> velocity=<-5, -3>
|
||||
position=<-29972, -50157> velocity=< 3, 5>
|
||||
position=< 40454, -30048> velocity=<-4, 3>
|
||||
position=< -9853, -9936> velocity=< 1, 1>
|
||||
position=< 40450, -19998> velocity=<-4, 2>
|
||||
position=< 30355, 30280> velocity=<-3, -3>
|
||||
position=<-39975, 30275> velocity=< 4, -3>
|
||||
position=< 50516, 30277> velocity=<-5, -3>
|
||||
position=< 40463, -50157> velocity=<-4, 5>
|
||||
position=< 50497, 30276> velocity=<-5, -3>
|
||||
position=<-29920, -9945> velocity=< 3, 1>
|
||||
position=< 30393, -9944> velocity=<-3, 1>
|
||||
position=< 30372, -19996> velocity=<-3, 2>
|
||||
position=< 20324, -40103> velocity=<-2, 4>
|
||||
position=< 40459, 30274> velocity=<-4, -3>
|
||||
position=< 10268, 50387> velocity=<-1, -5>
|
||||
position=<-50035, 20220> velocity=< 5, -2>
|
||||
position=<-29927, 50386> velocity=< 3, -5>
|
||||
position=<-50037, -30048> velocity=< 5, 3>
|
||||
position=< 20346, 30273> velocity=<-2, -3>
|
||||
position=< 40463, 10172> velocity=<-4, -1>
|
||||
position=< 50465, -40098> velocity=<-5, 4>
|
||||
position=<-19870, 10164> velocity=< 2, -1>
|
||||
position=< 30354, -50157> velocity=<-3, 5>
|
||||
position=< 30404, -19995> velocity=<-3, 2>
|
||||
position=<-50036, -50160> velocity=< 5, 5>
|
||||
position=< -9811, -9942> velocity=< 1, 1>
|
||||
position=<-19897, -40098> velocity=< 2, 4>
|
||||
position=<-19869, -19999> velocity=< 2, 2>
|
||||
position=<-19901, 40325> velocity=< 2, -4>
|
||||
position=<-19890, 30271> velocity=< 2, -3>
|
||||
position=< 30379, -9941> velocity=<-3, 1>
|
||||
position=< 40443, 20223> velocity=<-4, -2>
|
||||
position=< 40416, 30280> velocity=<-4, -3>
|
||||
position=< 40462, -50161> velocity=<-4, 5>
|
||||
position=<-50061, 30271> velocity=< 5, -3>
|
||||
position=<-19901, -30044> velocity=< 2, 3>
|
||||
position=< 40407, -50152> velocity=<-4, 5>
|
||||
position=<-39986, 20223> velocity=< 4, -2>
|
||||
position=<-29927, -30051> velocity=< 3, 3>
|
||||
position=< -9824, 50381> velocity=< 1, -5>
|
||||
position=< 50519, 30280> velocity=<-5, -3>
|
||||
position=< -9816, 30274> velocity=< 1, -3>
|
||||
position=<-39989, -9942> velocity=< 4, 1>
|
||||
position=<-29916, 10169> velocity=< 3, -1>
|
||||
position=< 40440, 40330> velocity=<-4, -4>
|
||||
position=< 20325, 50388> velocity=<-2, -5>
|
||||
position=< -9839, 20221> velocity=< 1, -2>
|
||||
position=<-19860, 20217> velocity=< 2, -2>
|
||||
position=<-40014, -9937> velocity=< 4, 1>
|
||||
position=< 50516, 30273> velocity=<-5, -3>
|
||||
position=<-40014, -50153> velocity=< 4, 5>
|
||||
position=< 30397, -19992> velocity=<-3, 2>
|
||||
position=< 20338, -19992> velocity=<-2, 2>
|
||||
position=< 20310, 30271> velocity=<-2, -3>
|
||||
position=< 10272, 10163> velocity=<-1, -1>
|
||||
position=<-39998, -40103> velocity=< 4, 4>
|
||||
position=< 40454, 40332> velocity=<-4, -4>
|
||||
position=<-29945, 50379> velocity=< 3, -5>
|
||||
position=<-40014, 40328> velocity=< 4, -4>
|
||||
position=< 50508, -40106> velocity=<-5, 4>
|
||||
position=< 40438, 10170> velocity=<-4, -1>
|
||||
position=< 10304, -9945> velocity=<-1, 1>
|
||||
position=< 20338, 40331> velocity=<-2, -4>
|
||||
position=<-19907, -19999> velocity=< 2, 2>
|
||||
position=<-19915, -19999> velocity=< 2, 2>
|
||||
position=<-29932, 40328> velocity=< 3, -4>
|
||||
position=< 50520, 40329> velocity=<-5, -4>
|
||||
position=< 20298, 10171> velocity=<-2, -1>
|
||||
position=<-40007, -30044> velocity=< 4, 3>
|
||||
position=< 30377, -30044> velocity=<-3, 3>
|
||||
position=<-29972, 30276> velocity=< 3, -3>
|
||||
position=< 10287, -30053> velocity=<-1, 3>
|
||||
position=< 20330, 20225> velocity=<-2, -2>
|
||||
position=<-50068, 20224> velocity=< 5, -2>
|
||||
position=< 30352, 20220> velocity=<-3, -2>
|
||||
position=< 40458, 50379> velocity=<-4, -5>
|
||||
position=< 30352, -9941> velocity=<-3, 1>
|
||||
position=<-29972, 50386> velocity=< 3, -5>
|
||||
position=<-50059, -40106> velocity=< 5, 4>
|
||||
position=<-50076, 10172> velocity=< 5, -1>
|
||||
position=< 10268, -9942> velocity=<-1, 1>
|
||||
position=< 30408, 50383> velocity=<-3, -5>
|
||||
position=<-40024, -40107> velocity=< 4, 4>
|
||||
position=< 50495, -50156> velocity=<-5, 5>
|
||||
position=<-39984, 50384> velocity=< 4, -5>
|
||||
position=< -9805, -9945> velocity=< 1, 1>
|
||||
position=< 50460, -30050> velocity=<-5, 3>
|
||||
position=< 30364, -30050> velocity=<-3, 3>
|
||||
position=< 40432, -30053> velocity=<-4, 3>
|
||||
position=< 10300, 50382> velocity=<-1, -5>
|
||||
position=< 30364, -30047> velocity=<-3, 3>
|
||||
position=<-19868, -40107> velocity=< 2, 4>
|
||||
position=<-39976, 40329> velocity=< 4, -4>
|
||||
position=<-29960, 40325> velocity=< 3, -4>
|
||||
position=< 30392, -50156> velocity=<-3, 5>
|
||||
position=< 10284, 50383> velocity=<-1, -5>
|
||||
position=< 50509, -9945> velocity=<-5, 1>
|
||||
position=<-29972, -30053> velocity=< 3, 3>
|
||||
position=< 40424, -19994> velocity=<-4, 2>
|
||||
position=<-40021, 20217> velocity=< 4, -2>
|
||||
position=<-50045, 50384> velocity=< 5, -5>
|
||||
position=< 10249, -30053> velocity=<-1, 3>
|
||||
position=< 20322, 10170> velocity=<-2, -1>
|
||||
position=< 20322, 10164> velocity=<-2, -1>
|
||||
position=<-50043, -30045> velocity=< 5, 3>
|
||||
position=< 30408, -19991> velocity=<-3, 2>
|
||||
position=<-29928, 50384> velocity=< 3, -5>
|
||||
position=< 10284, 30279> velocity=<-1, -3>
|
||||
position=< 40440, 20222> velocity=<-4, -2>
|
||||
position=< 20335, -9938> velocity=<-2, 1>
|
||||
position=<-19857, -19999> velocity=< 2, 2>
|
||||
position=<-40026, 50386> velocity=< 4, -5>
|
||||
position=<-40021, 10163> velocity=< 4, -1>
|
||||
position=< 30371, -50157> velocity=<-3, 5>
|
||||
position=< 50500, -40104> velocity=<-5, 4>
|
||||
position=<-29916, -19994> velocity=< 3, 2>
|
||||
position=<-29924, 20223> velocity=< 3, -2>
|
||||
position=<-39970, 20218> velocity=< 4, -2>
|
||||
position=< 40465, 50383> velocity=<-4, -5>
|
||||
position=<-29940, 40327> velocity=< 3, -4>
|
||||
@@ -0,0 +1,150 @@
|
||||
/----------------------\ /--------------------------\
|
||||
| /+------------------------------------------------------------------------------+-------------\ |
|
||||
| /--++--------------------------------------------------------\ | | |
|
||||
| | /++--------------------------------------------------------+---------------------+-------\ | |
|
||||
| /----------------+-+++--------\ /---------------------------------------------+---------------------+\ | | |
|
||||
| | | ||| | | /+---------------------++------+-----+-----------\|
|
||||
/----+-+-\ | ||| | | /----------------------------++---------------------++---\ | | ||
|
||||
| | | |/-------------+-+++--------+-+---------------+--->------------------------++--\ /------------++---+--+-----+---------\ ||
|
||||
| | | || /-------+-+++--------+-+---------------+----------------------------++--+-----+-----\ || | | | | ||
|
||||
/+----+-+-++-----+-------+-+++--------+-+---------------+----------------------------++--+--\ | | || | | | | ||
|
||||
|| |/+-++-----+-------+-+++--------+-+---------------+----------------------------++--+--+--+-----+-\ || | | | | ||
|
||||
/-----++----+++\|| | | ||| | | | || | | | | | || | | /--+---------+-++----\
|
||||
| || |||||| | | ||| | | /--+----------------------------++--+--+--+-----+-+----++---+--+--+--+------\ | || |
|
||||
| || |||||| | | ||| | | /--------+\ | /---------------------++--+--+--+-----+-+----++---+--+--+--+------+--+-++---\|
|
||||
| || ||||||/----+-------+-+++--------+-+---+--------++-+------+---------------------++--+--+--+-----+-+----++---+\ | | | | | || ||
|
||||
| || |||||||/---+-------+-+++--------+-+---+--------++-+------+----------------\ || | | | | | || || | | | | | || ||
|
||||
| || |||||||| | | ||| | | | || | | | || | | | | | /-++---++-+--+--+------+--+-++-\ ||
|
||||
| /--++----++++++++---+-------+-+++--\ /-+-+---+--------++-+------+----------------+----++--+--+\ | | | | || || | | | | | || | ||
|
||||
/+--+--++----++++++++---+-------+-+++--+---+-+-+---+--------++-+------+----------------+-\ || | || | | | | || || | | | | | || | ||
|
||||
|| | || |||||||| | | ||| | | | | | || | | | | ||/-+--++-+-----+-+--+-++\ || | | | | | || | ||
|
||||
|| | || |||||||| | | ||| | | | | | || | | /--------+-+--+++-+--++\| | | | ||| || | | | | | || | ||
|
||||
|| | || |||||||| | | ||| | | | | | || | | | | | ||| | |||| | | | ||| || | | | | | || | ||
|
||||
|| | || |||||^|| \-------+-+++--+---+-+-+---+--------++-+------+-------+--------+-+--+++-+--++++-----/ | | ||| || | | | | | || | ||
|
||||
|| | \+-<--++++++++-----------+-+++--+---+-+-+---+--------++-+------+-------+--------+-+--+++-+--/||| | | ||| || | | | | | || | ||
|
||||
|| | | |||||||| /----+-+++--+---+-+-+---+--------++-+----\ | | | | ||| | |||/------+--+-+++--++-+--+--+------+--+\|| | ||
|
||||
|| | | |||||||| | | |||/-+---+-+-+---+--------++-+----+-+-------+--------+-+--+++-+---++++------+--+-+++--++-+--+--+------+-\|||| | ||
|
||||
|| | | |||||||| | | |||| | /+-+-+---+--------++-+----+-+-------+--------+-+--+++-+---++++------+--+-+++--++-+--+--+--\ | ||||| | ||
|
||||
|| | | |||||||| | | \+++-+--++-+-+---+--------++-+----+-+-------+--------+-+--+++-+---++++------+--+-+++--++-/ | | | | ||||| | ||
|
||||
|| | | |||||||| | | ||| |/-++-+-+---+--------++-+----+\| | | | ||| | |||| | | ||| || | | | | ||||| | ||
|
||||
|| |/--+----++++++++---->-+----+--+++-++-++-+-+---+--------++-+---\||| | | | ||| | |||| |/-+-+++--++----+--+\ | | ||||| | ||
|
||||
|| || | |||||||| /+----+--+++-++-++-+-+---+--------++-+---++++-------+--------+-+--+++-+---++++------++-+-+++--++---\| || | | ||||| | ||
|
||||
|| || | |||||||| || | /+++-++-++\| | | || ^ |||| | | | ||| | ||||/-----++-+-+++--++---++--++-+---+\||||| | ||
|
||||
|| || |/---++++++++-----++----+-++++-++-++++-+---+--------++-+---++++-------+--------+-+--+++-+\/-+++++-----++-+-+++--++---++\ || | ||||||| | ||
|
||||
|| || || |||||||| || | |||| || |||| | | || | |||| | | | ||| ||| ||||| || | ||| || ||| || | ||||||| | ||
|
||||
|| || || |||||||| || | |||| || ||||/+---+--------++-+---++++-------+--------+-+\ ||| ||| ||||| || | ||| || ||| || | ||||||| | ||
|
||||
|| || /++---++++++++-----++----+-++++-++-++++++---+--------++-+---++++-------+--------+-++-+++-+++-+++++\ || | ||| || ||| || | ||||||| | ||
|
||||
|| || ||| |||||||| || |/++++-++-++++++---+--------++\| |||| | |/++-+++-+++-++++++--\ || | ||| || ||| || | ||||||| | ||
|
||||
|| || ||| |||||||| || |||||| || |||||| | |||| |||| \--------++++-+++-+++-+/|||| | || | ||| || ||| || | ||||||| | ||
|
||||
|\--++-+++---+++/|||| || |||||| || |||||| | |||| |||| /--------------++++-+++-+++-+-++++--+-++-+-+++--++---+++-++-+\ ||||||| | ||
|
||||
| \+-+++---+++-++++-----++----++++++-/| |||||| | |||| |||| | |||| ||| ||| | |||| | || | ||| || ||| || || ||||||| | ||
|
||||
| | ||| ||| |||| || |||||| /+-++++++---+--------++++---++++-+--------------++++-+++-+++-+-++++--+\|| | ||| || ||| || || ||||||| | ||
|
||||
| | ||| |\+-++++-----++----++++++-++-++++++---+--------++++---++++-+--------------++++-+++-+++-+-++++--++/| | ||| || ||| || || ||||||| | ||
|
||||
| | ||| | | |||| ||/---++++++-++-++++++---+--------++++---++++-+------------\ |||| ||| ||| | ||\+--++-+-+-+++--++---+++-++-++--+/||||| | ||
|
||||
| | ||| | | |||| ||| |||||| || |||||| | /------++++---++++-+------------+-++++-+++-+++-+-++-+--++-+-+-+++--++--\||| || || | ||||| | ||
|
||||
/+----+-+++---+\| |||| ||| |||||| || |||||| | | |||| |||| | | |||| ||| ||| | |\-+--++-+-+-+++--++--++++-++-++--+-++/|| | ||
|
||||
|| | ||| ||| |||| ||| |||||| || |||||| \-+------+/|\---++++-+------------+-++++-+++-+++-+-+--+--++-+-+-+++--/| |||| || || | || || | ||
|
||||
|| /-+-+++---+++-++++-\ ||| |||||| |\-++++++-----+------+-+----++/| | /----+-++++-+++-+++-+-+--+--++-+-+\||| | |||| || || | || || | ||
|
||||
|| | | ||| ||| |||| | ||| |||||| | ||||\+-----+------+-+----++-+-+-------+----+-+++/ ||| ||| | |/-+--++-+-+++++--\| |||| || || | || || | ||
|
||||
|| | | ||| ||| |||| | ||| |||||| | |||| | | | | || | | | | ||| ||| ||| | || | || | ||||| || |||| || || | || || | ||
|
||||
|| |/+-+++---+++-++++-+---+++---++++++-+--++++-+-----+------+-+----++-+-+-------+---\| ||| ||\-+++-+-++-+--++-+-++++/ || |||| || || | || || | ||
|
||||
|| ||| ||\---+++-++++-+---+++---++++++-+--++++-+-----+------+-+----++-+-+-------+---++-+++--++--+/| | \+-+--++-+-++++---++--++++-++-++--+-+/ || | ||
|
||||
|| ||| ||/---+++-++++-+---+++---++++++-+--++++-+-----+------+-+----++-+-+-----<-+---++-+++--++-\| | | | | || | ||\+---++--++++-++-++--+-+--+/ | ||
|
||||
|| ||| ||| ||| |||| | ||| |||||| | |||| | | | | || | | | || ||| ||/++-+-+--+-+--++-+-++-+---++\ |||| || || | | | | ||
|
||||
|| ||| ||| \++-++++-+---+++---++++/| | ||||/+-<---+------+-+----++-+-+-------+---++-+++--+++++-+\| | | || | || | ||| |||| || || | | | | ||
|
||||
|| ||| ||| || |||| | ||| |||| | | |||||| | | | /-++-+-+-------+---++-+++--+++++-+++--+-+-\|| | || | ||| |||| || || | | | | ||
|
||||
|| ||| ||| || |||| | ||| |||| | | |||||| | | | | || | | | || |\+--+++++-+++--+-+-+/|/+-++-+---+++-++++-++-++--+-+\ | | ||
|
||||
|| ||| ||| || |||| | ||| |||| | | |||||| | | | | || | | ^ || | | ||||| ||| | | | ||| || | ||| |||| || || | || | | ||
|
||||
|| ||| ||| || |||| | ||| |||| | | |||||| /--+------+-+--+-++-+-+-------+---++-+-+--+++++-+++--+-+-+-+++-++-+---+++-++++-++-++\ | || | | ||
|
||||
|| ||| ||| || |||| | ||| |||| | | |||||| | | | | | || | | \---++-+-+--+++++-+++--+-+-+-+++-+/ | ||| |||| || ||| | || | | ||
|
||||
|\--+++-+++----++-++++-+---+++---++++-+-+--++++++--+--+------+-+--+-++-+-+-----------++-+-/ ||||| ||| | | | ||| | | ||| |||| || ||| | || | | ||
|
||||
| ||| ||| || |||| | ||| |||| | | |||||| | /+------+\| | || | | || | ||||| ||| | | | ||| | | ||| |||| || ||| | || | | ||
|
||||
| ||| ||| || |||| | ||| |||| | | |||||| | || ||| | || | |/----------++-+----+++++-+++--+-+-+-+++-+--+---+++-++++-++\||| | || | | ||
|
||||
| ||\-+++----++-++++-+---+++---++++-+-+--++++++--+-++------+++--+-/| | || || | ||||| ||| | | | |||/+--+---+++-++++-++++++-+-++-+--+\||
|
||||
|/--++--+++----++-++++-+\ ||| |||| | |/-++++++--+-++------+++--+--+-+-++----------++-+----+++++-+++--+-+-+-+++++--+---+++-++++<++++++-+-++-+\ ||||
|
||||
|| || ||| /-++-++++-++--+++---++++-+-++-++++++--+-++------+++--+--+-+-++----------++-+----+++++-+++--+-+-+-+++++--+\ ||| |||| |||||| | || || ||||
|
||||
|| || ||| | || ||||/++--+++---++++-+-++-++++++--+-++------+++--+--+-+-++----------++-+----+++++-+++--+-+-+\||||| || ||| |||| |||||| | || || ||||
|
||||
||/-++--+++--+-++-+++++++--+++---++++-+\|| |||||\--+-++------+++--+--+-+-++----------++-+----+++++-+++--+-+-+++++++--/| ||| |||| |||||| | || || ||||
|
||||
||| || ||| | || ||||||| ||| |||| |||| ||||| /-+-++------+++--+--+-+-++--------\ || | ||||| ||| | | ||||||| /+--+++-++++-++++++-+-++-++\||||
|
||||
||| || ||| | || ||||||| ||| |||| |||| ||||| | | || ||| | | | || | || | ||||| ||| | | ||||||| || ||| |||| |||||| | || |||||||
|
||||
||| || ||| | || ||||||| |\+---++++-++++-+++++-+-+-++------+++--+--/ | || /---+-++-+----+++++-+++--+-+-+++++++--++--+++-++++\|||||| | || |||||||
|
||||
||| || ||| | || ||\++++--+-+---++++-++++-+++++-+-+-++------+++--+----+-++----+---+-++-+----+++++-+++--+-+-+++++++--++--+/| ||||||||||| | || |||||||
|
||||
||| || ||| | || || |||| | | |||| |||| \++++-+-+-++------+++--+----+-++----+---+-++-+----+++++-+++--+-+-+++++++--++--+-+-++++++++/|| | || |||||||
|
||||
||| || ||| | || || |v|| | | /++++-++++--++++-+-+-++------+++--+----+-++-\ | | || | ||||| ||| | | ||||||| || | | |||||||| || | || |||||||
|
||||
||v || /+++--+-++-++-++++--+-+--+++++-++++--++++-+-+-++------+++--+----+-++-+--+---+-++-+----+++++-+++--+-+\||||||| || | | |||||||| || | || |||||||
|
||||
||| || |||| | || || |||| | | ||||| |||| |||| | | || ||| |/---+-++-+-\| | || | ||||| ||| | ||||||||| || | | |||||||| || | || |||||||
|
||||
||| || |||| | || || |||| | | ||||| |||| |||| | | || ||| || | || | ||/--+-++-+----+++++-+++--+-+++++++++\ || | | |||||||| || | || |||||||
|
||||
||| || |||| | || || |||| | | |||\+-++++--+/|| | | || ||| || \-++-+-+++--+-++-+----+++++-+++--+-++++++++++-++--+-+-++++++++-++-+-++-+++++/|
|
||||
||| || |||| | || || |||| | | ||| | |||| | || | | || ||| || || | ||| | || | ||||| ||| | |||||||||| \+--+-+-++++++++-++-+-++-++/|| |
|
||||
||| || |||| \-++-++-++++--+-+--+++-+-++++--+-++-+-+-++------+++--++-----++-+-+++--+-++-+----+++++-+++--+-++++++++++--/ | | ||\+++++-++-+-++-++-++-/
|
||||
||| || |||| || || |||| | | ||| | \+++--+-++-+-+-++------+++--++-----++-+-+++--+-++-+----+++++-+++--+-++++++++++-----+-+-++-+++++-++-+-/| || ||
|
||||
||| || |||| ||/++-++++--+-+--+++-+--+++--+-++-+-+-++------+++--++-----++-+-+++--+-++-+----+++++-+++--+-++++++++++-----+-+\|| ||||| || | | || ||
|
||||
||| || |||\----+++++-++++--+-+--+++-+--+++--+-++-+-+-++------+++--++-----++-+-+++--+-++-+----+++/| ||| | |||||||||| | |||| ||||| || | | || ||
|
||||
||| || ||| ||||| |||| | | ||| | ||| | || | | || ||| || || | ||| | || | ||| | ||| \-++++++++++-----/ |||| ||||| || | | || ||
|
||||
|\+-++-+++-----+++++-+++/ | | ||| | ||\--+-++-+-+-++------+++--++-----++-+-+++--+-++-+----+++-+-+++----++++++++++-------++++-+++++-++-+--+-+/ ||
|
||||
| | || ||| ||||| ||| | | ||| | || | || | | || ||| || || | |||/-+-++-+----+++-+-+++----++++++++++-------++++-+++++-++-+\ | | ||
|
||||
| | || ||| ||||| ||| /-+-+--+++-+--++\ | || | | || /----+++--++-----++-+-++++-+-++-+----+++-+-+++----++++++++++-------++++-+++++-++-++-+-+--++-\
|
||||
| | || ||| ||||| ||| | | | ||| | ||| | || | | || | ||| || || | |||| | || | \++-+-+++----++++++++++-------++++-+++++-++-++-+-/ || |
|
||||
| | || ||\-----+++/| ||| | | | ||| | ||| | || | | || | ||| || || | |||| | || | |\-+-+++----++++++++++-------/||| ||||| || || | || |
|
||||
| | || || /---+++-+-+++-+-+-+--+++-+--+++--+-++-+-+-++-+----+++--++-----++-+-++++-+-++-+-----+--+-+++----++++++++++--\ ||| ||||| || || | || |
|
||||
\-+-++-++--+---/|| | ||| | | | ||| | ||| | || | | || | ||| || || | |||| | || | | | \++----++++++++++--+-----+++-/|||| || || | || |
|
||||
| || || | || | ||| | | | ||| | ||| | || | | || | ||| || || | |||| | || | | | || |||||||||| | ||| |||| || || | || |
|
||||
| || || | \+-+-+++-+-+-+--+++-+--+++--+-/| | | || | ||| || || | |||| | || | | | ||/---++++++++++--+-----+++--++++-++-++-+\ || |
|
||||
| || || /+-----+-+-+++-+-+-+--+++-+--+++--+--+-+-+-++-+----+++-\|| || | |||| | || | | | ||| |||||||||| | ||| ||^| || || || || |
|
||||
| || || || | | ||| | | | ||| | ||| | | | | || | ||| ||| || | |||| | || | | | ||| |||||||||| | ||| |||| || || || || |
|
||||
| || || || | | ||| | | | ||| | ||| | | | | || | ||| ||| || | ||||/+-++-+-----+--+-\||| |||||||||| | ||| |||| || || || || |
|
||||
/-+-++-++-++-----+-+-+++-+-+-+--+++-+--+++--+--+-+-+-++\| ||| ||| || | |||\++-++-+-----+--+-++++---++++++++++--+-----+++--++++-++-+/ || || |
|
||||
| | ||/++-++-----+-+-+++-+-+-+--+++-+--+++--+--+-+-+-++++----+++-+++\ || | ||| || || | | | |||| |||||||||| | ||| |||| || | || || |
|
||||
| | ||||| || | | ||| | |/+--+++-+--+++--+--+-+-+-++++----+++-++++----++-+-+++-++-++-+-----+--+-++++---++++++++++--+-----+++-\|||| || | || || |
|
||||
| | |||||/++-----+-+-+++\| ||| ||| \--+++--+--+-+-+-++++----+++-++++----++-+-+++-++-++-+-----+--+-++++---++++++++++--+-----+++-++/|| || | || || |
|
||||
| | |||||||| | | ||||| ||| |\+----+++--+--+-+-+-++++----+++-++++----++-+-+++-++-++-+-----/ | |||| ||||||||\+--+-----+++-++-++-++-+--++---/| |
|
||||
| | |||||||| | | ||||| ||| | | ||| | | | | |||| ||| |||| || | ||| || || | | |||| |||||||| | | ||| || || || | || | |
|
||||
| | |||||||| | | ||||| ||| | | ||| | | | | |||| \++-++++--->++-+-+++-++-++-+--------+-++++---++++++++-+--+-----+++-++-++-++-/ || | |
|
||||
| | |||||||| | | ||||| ||| | | /-+++--+--+-+-+-++++-----++-++++\ || | ||| || || | | |||| |||||||| | | ||| || || || || | |
|
||||
| | |||||||| | | ||||| ||| | | | ||| | | | | |||| || ||||| || | ||| || || | | |||| |||||||| | | ||| || || || || | |
|
||||
| | |||||||| | | ||||| ||| \-+--+-+++--+--+-+-+-++++-----++-+++++>--++-/ ||| || || | | |||| |||||||| | | ||| || || || || | |
|
||||
| | |||||||| | | ||||| ||| /+--+-+++--+--+\| | |||| || ||||| || ||| || || | | |||\---++++++++-+--+-----+++-++-++-++----+/ | |
|
||||
| \-++++++++-----+-+-+++++-+++---++--+-/|| | ||| | |||| || ||||| /++---+++-++-++-+--------+\||| |||||||| | | ||| || || || | | |
|
||||
| |||||||| | | ||||| ||| || | || | \++-+-++++-----++-+++++--+++---+++-++-++-+--------+++/| |||||||| | | ||| || || || | | |
|
||||
| ||||||\+-----+-+-+++++-+++---++--+--++--+---++-+-++++-----++-/|||| ||| ||| || ||/+--------+++-+----++++++++-+--+-----+++-++-++-++----+\ | |
|
||||
| |||||| | | \-+++++-+++---++--+--++--+---++-+-++++-----++--++++--+++---+++-++-++++--------/|| | ||||||\+-+--+-----+++-++-/|/++----++\ | |
|
||||
| |||||| | | ||||| ||| || | \+--+---++-+-++++-----++--++++--+++---+++-++-++++---------++-+----++++/| | | | ||| || |||| ||| | |
|
||||
| |||||| | | ||||| ||| || | | | || | |||| || |||| |\+---+++-++-++++---------++-+----++++-+-+-+--+-----+++-++--++/| ||| | |
|
||||
| |||||| | /+---+++++-+++---++--+---+--+---++-+-++++-----++--++++--+-+---+++-++-++++---------++-+----++++-+-+-+--+\ ||| || || | ||| | |
|
||||
| |||||\-+----++---+++/| ||| || | | | || | |||| || |||| | | ||| || |||| || | |||| | | | || ||| || || | ||| | |
|
||||
| ||||| | /-++---+++-+-+++---++--+---+--+---++-+-++++-----++--++++-\| \---+++-++-++++---------++-+----++++-+-+-+--++----+++-++--/| | ||| | |
|
||||
| ||||| | | || ||| | ||\---++--+---+--+---++-+-++++-----++--++++-++-----+++-++-+/|| || | /-++++-+-+-+--++----+++-++---+-+----+++-\ | |
|
||||
| ||||| | | || ||| | || \+--+---+--+---/| | |||| || |||| || ||| || | || || | | |||| | | | || /+++-++---+-+----+++-+-+\|
|
||||
| ||||| | | || ||| | || | | | | | | |||| || |||| || ||| \+-+-++---------+/ | | |||| | | | || |||| || | | ||| | |||
|
||||
| ||||| | | || ||| | |\-----+--+---+--+----+-+-++++-----++--++++-++-----+++--+-+-++---------+--+--+-++++-+-+-+--++---++++-/| | | ||| | |||
|
||||
| ||||| | | || ||| | \------+--+---+--+----+-+-++++-----++--++++-++-----+++--+-+-++---------+--+--+-++++-+-+-+--++---+++/ | | | ||| | |||
|
||||
| ||||| | | || \++-+--------+--+---+--+----+-+-++++-----++--++++-++-----+++--+-+-+/ | | | |||| |/+-+--++---+++---+--\| | ||| | |||
|
||||
\---+++++--+--+-++----++-+--------+--+---+--+----+-+-++/| || |||| || ||| | | | | | | |||| ||| | || ||| | || | ||| | |||
|
||||
||||| | | || || \--------+--+---/ | | | || | || |||| || ||| | | \----------+--+--+-++++-+++-+--++---+++---+--++-+----+/| | |||
|
||||
||||| | | || /--++----------+--+--\ | | \-++-+-----++--++++-++-----+++--+-+------------+--+--+-++++-+++-+--++---+++---+--++-/ | | | |||
|
||||
||||| | | || | || | | | \----+---++-+-----++--++++-++-----+++--+-+------------+--/ | |||| ||| | || ||| | || | | | |||
|
||||
||||| | | || | || | | | | |\-+-----++--++++-++-----+++--+-+------------+-----+-++++-+++-+--++---++/ | || | | | |||
|
||||
||||| \--+-++-+--++----------+--+--+--------+---+--+-----++--++++-++-----+++--+-+------------+-----+-++++-+++-+--/| || | || | | | |||
|
||||
|\+++-----+-++-+--++----------+--+--+--------+---+--+-----++--++++-++-----+++--+-/ | | |||| ||| | | || | || | | | |||
|
||||
| ||| /--+-++-+--++----------+--+--+--------+---+--+-----++--++++-++-----+++\ | | | |||| ||| | | || | || | | | |||
|
||||
| ||| | | || | || | | | | | \-----++--++++-++-----++++-+--------------+-----+-++++-+++-+---+---++----+--++------+-+-+-++/
|
||||
| ||| | | || |/-++----------+--+--+--------+---+----\ || |||| || |||| | | | |||| ||| | | || v || | | | ||
|
||||
| ||| | | || || || | | | \---+----+---++--++++-++-----++++-/ | | |||| ||| | | || | || | | | ||
|
||||
/--+-+++--+-\| || || || | | | | | || |||| || |||| | | |||| ||| | | || | || | | | ||
|
||||
| | ||| | || || \+-++----------+->+--/ | | || |\++-++-----/||| | | |||| ||| | | || | || | | | ||
|
||||
| | ||| | || || | || | | | | || | || || ||| /+-----+-++++-+++-+---+---++----+--++------+-+-+-++\
|
||||
| | ||\--+-++-++--+-++--->------+--+---------------+----+---++--+-++-++------+++---------------++-----+-/||| ||| | | || | || | | | |||
|
||||
| | || | || || | || \--+---------------+----+---+/ | || || ||| || | ||| |\+-+---+---++----+--/| | | | |||
|
||||
| | || | || || | \+-------------+---------------+----+---+---+-++-++------+++---------------++-----+--++/ | | | | || | | | | | |||
|
||||
| | || | |\-++--+--+-------------+---------------+----+---+---+-++-/| |\+---------------++-----+--++--+-+-/ | || | \------+-/ | |||
|
||||
| | || | | || | | | | | | | || \------+-+---------------+/ | || | | | || | | | |||
|
||||
| \-++---+-+--++--+--/ \---------------+----+---+---+-+/ | | | \--++--+-+-----+---++----+----------+---/ |||
|
||||
| |\---+-+--++--+--------------------------------+----+---+---+-+----------+-+---------------+---------/| | \-----+---++----+----------+-----/||
|
||||
\----+----+-/ || | \----+---/ | | | | | | | | || | | ||
|
||||
| | || | | \-+----------+-+---------------+----------/ | | || | | ||
|
||||
| | \+--+-------------------------------------+---------+----------+-+---------------+-------------+-------/ \+----+----------+------/|
|
||||
| | \--+-------------------------------------+---------+----------+-+---------------+-------------+------------/ | | |
|
||||
| \--------+-------------------------------------+---------+----------+-/ | | | | |
|
||||
| \-------------------------------------/ | \-----------------+-------------+-----------------/ | |
|
||||
| | | \----------------------------/ |
|
||||
\-------------------------------------------------------------/ \--------------------------------------------------/
|
||||
@@ -0,0 +1,32 @@
|
||||
################################
|
||||
#########################.G.####
|
||||
#########################....###
|
||||
##################.G.........###
|
||||
##################.##.......####
|
||||
#################...#.........##
|
||||
################..............##
|
||||
######..########...G...#.#....##
|
||||
#####....######.G.GG..G..##.####
|
||||
#######.#####G............#.####
|
||||
#####.........G..G......#...####
|
||||
#####..G......G..........G....##
|
||||
######GG......#####........E.###
|
||||
#######......#######..........##
|
||||
######...G.G#########........###
|
||||
######......#########.....E..###
|
||||
#####.......#########........###
|
||||
#####....G..#########........###
|
||||
######.##.#.#########......#####
|
||||
#######......#######.......#####
|
||||
#######.......#####....E...#####
|
||||
##.G..#.##............##.....###
|
||||
#.....#........###..#.#.....####
|
||||
#.........E.E...#####.#.#....###
|
||||
######......#.....###...#.#.E###
|
||||
#####........##...###..####..###
|
||||
####...G#.##....E####E.####...##
|
||||
####.#########....###E.####....#
|
||||
###...#######.....###E.####....#
|
||||
####..#######.##.##########...##
|
||||
####..######################.###
|
||||
################################
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,20 +1,20 @@
|
||||
//
|
||||
// Advent of Code 2018 "Day 1: Chronal Calibration"
|
||||
// Advent of Code 2018 "Day xx: Something Something"
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class Chronal {
|
||||
class Template {
|
||||
}
|
||||
|
||||
class Day01: AOCDay {
|
||||
lazy var tests: (() -> ()) = day01Tests
|
||||
lazy var final: (() -> ()) = day01Final
|
||||
class Dayxx: AOCDay {
|
||||
lazy var tests: (() -> ()) = dayxxTests
|
||||
lazy var final: (() -> ()) = dayxxFinal
|
||||
|
||||
func day01Tests() {
|
||||
func dayxxTests() {
|
||||
}
|
||||
|
||||
func day01Final() {
|
||||
func dayxxFinal() {
|
||||
let retVal = "None"
|
||||
print("Answer to part 1 is: \(retVal)")
|
||||
print("Answer to part 2 is: \(retVal)")
|
||||
|
||||
+136
-3
@@ -5,18 +5,151 @@
|
||||
import Foundation
|
||||
|
||||
class Chronal {
|
||||
fileprivate var adjustments: [Int] = []
|
||||
let startingFreq = 0
|
||||
|
||||
// Supply filename for input ex: '/home/peterr/AOC2018/Sources/AOC2018/data/day01.txt'
|
||||
init(withFile filename: String) {
|
||||
let adjString = Tools.readFile(fromPath: filename)
|
||||
var adjustmentArray: [String] = []
|
||||
adjustmentArray = adjString.components(separatedBy: "\n")
|
||||
adjustments = []
|
||||
for val in adjustmentArray {
|
||||
if let intVal = Int(val) {
|
||||
adjustments.append(intVal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Supply test data in the form of a String
|
||||
init(withString adjString: String) {
|
||||
var adjustmentArray: [String] = []
|
||||
adjustmentArray = adjString.components(separatedBy: ", ")
|
||||
adjustments = []
|
||||
for val in adjustmentArray {
|
||||
if let intVal = Int(val) {
|
||||
adjustments.append(intVal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply all the adjustments that this class was initialized with
|
||||
// Return the resulting frequency as an Optional (nil => no adjustments)
|
||||
func applyAdjustments() -> Int? {
|
||||
var retVal: Int?
|
||||
if adjustments.count > 0 {
|
||||
var sum = 0
|
||||
for val in adjustments {
|
||||
sum += val
|
||||
}
|
||||
retVal = sum
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func repeatedAjustmentUntilTwice() -> Int {
|
||||
var retVal = -1
|
||||
if adjustments.count > 0 {
|
||||
var usedFreqs = [Int: Int]()
|
||||
var sum = 0
|
||||
usedFreqs[sum] = 1
|
||||
var noRepeats = true
|
||||
repeat {
|
||||
for val in adjustments {
|
||||
sum += val
|
||||
if usedFreqs[sum] != nil {
|
||||
retVal = sum
|
||||
noRepeats = false
|
||||
break
|
||||
} else {
|
||||
usedFreqs[sum] = 1
|
||||
}
|
||||
}
|
||||
} while noRepeats
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
}
|
||||
|
||||
class Day01: AOCDay {
|
||||
lazy var tests: (() -> ()) = day01Tests
|
||||
lazy var final: (() -> ()) = day01Final
|
||||
|
||||
func testInitWithFile() {
|
||||
let chrona = Chronal(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day01.txt")
|
||||
XCTAssertEqual(test: "testInitWithFile", withExpression: (chrona.adjustments.count == 990))
|
||||
if chrona.adjustments.count == 990 {
|
||||
XCTAssertEqual(test: "testInitWithFile index[10]", withExpression: (chrona.adjustments[10] == -17))
|
||||
XCTAssertEqual(test: "testInitWithFile index[989]", withExpression: (chrona.adjustments[989] == 124726))
|
||||
}
|
||||
}
|
||||
|
||||
// +1, +1, +1 results in 3
|
||||
// +1, +1, -2 results in 0
|
||||
// -1, -2, -3 results in -6
|
||||
func testInitWithString() {
|
||||
var chrona = Chronal(withString: "+1, +1, +1")
|
||||
XCTAssertEqual(test: "testInitWithString", withExpression: (chrona.adjustments.count == 3))
|
||||
if chrona.adjustments.count == 3 {
|
||||
XCTAssertEqual(test: "testInitWithString index[1]", withExpression: (chrona.adjustments[1] == 1))
|
||||
}
|
||||
chrona = Chronal(withString: "+1, +1, -2")
|
||||
XCTAssertEqual(test: "testInitWithString", withExpression: (chrona.adjustments.count == 3))
|
||||
if chrona.adjustments.count == 3 {
|
||||
XCTAssertEqual(test: "testInitWithString index[1]", withExpression: (chrona.adjustments[1] == 1))
|
||||
}
|
||||
chrona = Chronal(withString: "-1, -2, -3")
|
||||
XCTAssertEqual(test: "testInitWithString", withExpression: (chrona.adjustments.count == 3))
|
||||
if chrona.adjustments.count == 3 {
|
||||
XCTAssertEqual(test: "testInitWithString index[1]", withExpression: (chrona.adjustments[1] == -2))
|
||||
}
|
||||
}
|
||||
|
||||
func testApplyAdjustments() {
|
||||
var chrona = Chronal(withString: "+1, +1, +1")
|
||||
var val = chrona.applyAdjustments()
|
||||
XCTAssertEqual(test: "testApplyAdjustments", withExpression: (val == 3))
|
||||
chrona = Chronal(withString: "+1, +1, -2")
|
||||
val = chrona.applyAdjustments()
|
||||
XCTAssertEqual(test: "testApplyAdjustments", withExpression: (val == 0))
|
||||
chrona = Chronal(withString: "-1, -2, -3")
|
||||
val = chrona.applyAdjustments()
|
||||
XCTAssertEqual(test: "testApplyAdjustments", withExpression: (val == -6))
|
||||
}
|
||||
|
||||
// +1, -1 first reaches 0 twice.
|
||||
// +3, +3, +4, -2, -4 first reaches 10 twice.
|
||||
// -6, +3, +8, +5, -6 first reaches 5 twice.
|
||||
// +7, +7, -2, -7, -4 first reaches 14 twice.
|
||||
|
||||
func testRepeatedAjustmentUntilTwice() {
|
||||
var chrona = Chronal(withString: "+1, -1")
|
||||
var val = chrona.repeatedAjustmentUntilTwice()
|
||||
XCTAssertEqual(test: "testRepeatedAjustmentUntilTwice", withExpression: (val == 0))
|
||||
chrona = Chronal(withString: "+3, +3, +4, -2, -4")
|
||||
val = chrona.repeatedAjustmentUntilTwice()
|
||||
XCTAssertEqual(test: "testRepeatedAjustmentUntilTwice", withExpression: (val == 10))
|
||||
chrona = Chronal(withString: "-6, +3, +8, +5, -6")
|
||||
val = chrona.repeatedAjustmentUntilTwice()
|
||||
XCTAssertEqual(test: "testRepeatedAjustmentUntilTwice", withExpression: (val == 5))
|
||||
chrona = Chronal(withString: "+7, +7, -2, -7, -4")
|
||||
val = chrona.repeatedAjustmentUntilTwice()
|
||||
XCTAssertEqual(test: "testRepeatedAjustmentUntilTwice", withExpression: (val == 14))
|
||||
}
|
||||
|
||||
func day01Tests() {
|
||||
testInitWithFile()
|
||||
testInitWithString()
|
||||
testApplyAdjustments()
|
||||
testRepeatedAjustmentUntilTwice()
|
||||
}
|
||||
|
||||
func day01Final() {
|
||||
let retVal = "None"
|
||||
print("Answer to part 1 is: \(retVal)")
|
||||
print("Answer to part 2 is: \(retVal)")
|
||||
let chrona = Chronal(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day01.txt")
|
||||
if let val = chrona.applyAdjustments() {
|
||||
print("Answer to part 1 is: \(val)")
|
||||
}
|
||||
let twice = chrona.repeatedAjustmentUntilTwice()
|
||||
print("Answer to part 2 is: \(twice)")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,206 @@
|
||||
//
|
||||
// Advent of Code 2018 "Day 2: Inventory Management System"
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class Inventory {
|
||||
var IDarray: [String] = []
|
||||
var IDarrayOfdict: [[Character : Int]] = []
|
||||
var validIDs: [String] = []
|
||||
|
||||
// Supply filename for input ex: '/home/peterr/AOC2018/Sources/AOC2018/data/day02.txt'
|
||||
init(withFile filename: String) {
|
||||
let IDs = Tools.readFile(fromPath: filename)
|
||||
IDarray = IDs.components(separatedBy: "\n")
|
||||
// This gurd statement is just an excuse to use guard
|
||||
// I'm assuming the last string is an empty string, if not DON'T remove the last string
|
||||
guard let lastStr = IDarray.last, lastStr.count == 0 else { return }
|
||||
IDarray.removeLast() // empty string
|
||||
}
|
||||
|
||||
// Supply test data in the form of a String
|
||||
init(withString IDs: String) {
|
||||
IDarray = IDs.components(separatedBy: "\n")
|
||||
}
|
||||
|
||||
func createDictionaryCount(withID ID: String) -> [Character : Int] {
|
||||
var retVal: [Character : Int] = [:]
|
||||
for idChar in ID {
|
||||
|
||||
if let count = retVal[idChar] {
|
||||
retVal[idChar] = count + 1
|
||||
} else {
|
||||
retVal[idChar] = 1
|
||||
}
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func createArrayOfDicts() {
|
||||
for idStr in IDarray {
|
||||
IDarrayOfdict.append( createDictionaryCount(withID: idStr))
|
||||
}
|
||||
}
|
||||
|
||||
func countExactlyNLetters(number: Int) -> Int {
|
||||
var retVal = 0
|
||||
if IDarrayOfdict.count < 1 {
|
||||
createArrayOfDicts()
|
||||
}
|
||||
// Set up new dictionary of combination of all
|
||||
for index in 0..<IDarrayOfdict.count {
|
||||
for (_, count) in IDarrayOfdict[index] {
|
||||
if count == number {
|
||||
retVal += 1
|
||||
validIDs.append(IDarray[index])
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func computeChecksum() -> Int {
|
||||
let twos = countExactlyNLetters(number: 2)
|
||||
let threes = countExactlyNLetters(number: 3)
|
||||
return twos * threes
|
||||
}
|
||||
|
||||
// Find IDs that differ by only one character at the identical location
|
||||
// Use a diff filter on the output of 'zip' (zip : Creates a sequence of pairs built out of two underlying sequences)
|
||||
// Only add the indicies of the IDs if there is only one diff
|
||||
func determineListOfCandidates() -> (box1: Int, box2: Int) {
|
||||
var retVal: (box1: Int, box2: Int) = (0,0)
|
||||
var difference: [(Character, Character)] = []
|
||||
for index in 0..<IDarray.count-1 {
|
||||
for inner in index+1..<IDarray.count {
|
||||
difference = zip(IDarray[index], IDarray[inner]).filter{ $0 != $1 }
|
||||
if difference.count == 1 {
|
||||
retVal = (index, inner)
|
||||
}
|
||||
}
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
}
|
||||
|
||||
class Day02: AOCDay {
|
||||
lazy var tests: (() -> ()) = day02Tests
|
||||
lazy var final: (() -> ()) = day02Final
|
||||
|
||||
let testString = """
|
||||
abcdef
|
||||
bababc
|
||||
abbcde
|
||||
abcccd
|
||||
aabcdd
|
||||
abcdee
|
||||
ababab
|
||||
"""
|
||||
let testStringPart2 = """
|
||||
abcde
|
||||
fghij
|
||||
klmno
|
||||
pqrst
|
||||
fguij
|
||||
axcye
|
||||
wvxyz
|
||||
"""
|
||||
|
||||
func testInventoryInitWithFile() {
|
||||
let inv = Inventory(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day02.txt")
|
||||
XCTAssertEqual(test: "testInventoryInitWithFile count", withExpression: (inv.IDarray.count == 250))
|
||||
XCTAssertEqual(test: "testInventoryInitWithFile [3]", withExpression: (inv.IDarray[3] == "fonwsmjyquwrapeczikghttdpl"))
|
||||
if let lastString = inv.IDarray.last {
|
||||
XCTAssertEqual(test: "testInventoryInitWithFile [last]", withExpression: (lastString == "fonbdmjyqujsapeczikghtvdxl"))
|
||||
}
|
||||
}
|
||||
|
||||
// abcdef contains no letters that appear exactly two or three times.
|
||||
// bababc contains two a and three b, so it counts for both.
|
||||
// abbcde contains two b, but no letter appears exactly three times.
|
||||
// abcccd contains three c, but no letter appears exactly two times.
|
||||
// aabcdd contains two a and two d, but it only counts once.
|
||||
// abcdee contains two e.
|
||||
// ababab contains three a and three b, but it only counts once.
|
||||
func testInventoryInitWithString() {
|
||||
let inv = Inventory(withString: testString)
|
||||
XCTAssertEqual(test: "testInventoryInitWithString count", withExpression: (inv.IDarray.count == 7))
|
||||
XCTAssertEqual(test: "testInventoryInitWithString [3]", withExpression: (inv.IDarray[3] == "abcccd"))
|
||||
if let lastString = inv.IDarray.last {
|
||||
XCTAssertEqual(test: "testInventoryInitWithString [last]", withExpression: (lastString == "ababab"))
|
||||
}
|
||||
}
|
||||
|
||||
func testCreateDictionaryCount() {
|
||||
let inv = Inventory(withString: testString)
|
||||
var dict = inv.createDictionaryCount(withID: inv.IDarray[0])
|
||||
XCTAssertEqual(test: "testCreateDictionaryCount [0][a]", withExpression: (dict["a"] == 1))
|
||||
dict = inv.createDictionaryCount(withID: inv.IDarray[1])
|
||||
XCTAssertEqual(test: "testCreateDictionaryCount [1][a]", withExpression: (dict["a"] == 2))
|
||||
XCTAssertEqual(test: "testCreateDictionaryCount [1][b]", withExpression: (dict["b"] == 3))
|
||||
dict = inv.createDictionaryCount(withID: inv.IDarray[6])
|
||||
XCTAssertEqual(test: "testCreateDictionaryCount [6][a]", withExpression: (dict["a"] == 3))
|
||||
XCTAssertEqual(test: "testCreateDictionaryCount [6][b]", withExpression: (dict["b"] == 3))
|
||||
}
|
||||
|
||||
func testCreateArrayOfDicts() {
|
||||
let inv = Inventory(withString: testString)
|
||||
inv.createArrayOfDicts() //inv.IDarrayOfdict[][]
|
||||
|
||||
XCTAssertEqual(test: "testCreateArrayOfDicts count", withExpression: (inv.IDarrayOfdict.count == 7))
|
||||
if inv.IDarrayOfdict.count > 6 {
|
||||
XCTAssertEqual(test: "testCreateArrayOfDicts [0][a]", withExpression: (inv.IDarrayOfdict[0]["a"] == 1))
|
||||
XCTAssertEqual(test: "testCreateArrayOfDicts [1][a]", withExpression: (inv.IDarrayOfdict[1]["a"] == 2))
|
||||
XCTAssertEqual(test: "testCreateArrayOfDicts [1][b]", withExpression: (inv.IDarrayOfdict[1]["b"] == 3))
|
||||
XCTAssertEqual(test: "testCreateArrayOfDicts [6][a]", withExpression: (inv.IDarrayOfdict[6]["a"] == 3))
|
||||
XCTAssertEqual(test: "testCreateArrayOfDicts [6][b]", withExpression: (inv.IDarrayOfdict[6]["b"] == 3))
|
||||
}
|
||||
}
|
||||
|
||||
func testCountExactlyNLetters() {
|
||||
let inv = Inventory(withString: testString)
|
||||
let twos = inv.countExactlyNLetters(number: 2)
|
||||
XCTAssertEqual(test: "testCountExactlyNLetters 2", withExpression: (twos == 4))
|
||||
let threes = inv.countExactlyNLetters(number: 3)
|
||||
XCTAssertEqual(test: "testCountExactlyNLetters 3", withExpression: (threes == 3))
|
||||
}
|
||||
|
||||
func testComputeChecksum() {
|
||||
let inv = Inventory(withString: testString)
|
||||
let checksum = inv.computeChecksum()
|
||||
XCTAssertEqual(test: "testComputeChecksum", withExpression: (checksum == 12))
|
||||
}
|
||||
|
||||
func testDetermineListOfCandidates() {
|
||||
let inv = Inventory(withString: testStringPart2)
|
||||
let candidate = inv.determineListOfCandidates()
|
||||
XCTAssertEqual(test: "testDetermineListOfCandidates", withExpression: (candidate == (1, 4)))
|
||||
}
|
||||
|
||||
func day02Tests() {
|
||||
testInventoryInitWithFile()
|
||||
testInventoryInitWithString()
|
||||
testCreateDictionaryCount()
|
||||
testCreateArrayOfDicts()
|
||||
testCountExactlyNLetters()
|
||||
testComputeChecksum()
|
||||
testDetermineListOfCandidates()
|
||||
}
|
||||
|
||||
func day02Final() {
|
||||
// let retVal = "None"
|
||||
let inv = Inventory(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day02.txt")
|
||||
let checksum = inv.computeChecksum()
|
||||
let ID = inv.determineListOfCandidates()
|
||||
print("Answer to part 1 is: \(checksum)")
|
||||
|
||||
var answer = ""
|
||||
let answerChars = zip(inv.IDarray[ID.box1], inv.IDarray[ID.box2]).filter{ $0 == $1 }
|
||||
for tuple in answerChars {
|
||||
answer.append(tuple.0)
|
||||
}
|
||||
print("Answer to part 2 is: \(answer)")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
//
|
||||
// Advent of Code 2018 "Day 3: No Matter How You Slice It"
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct ElfSquare {
|
||||
var ID = 0
|
||||
var loc = (fromLeft: 0, fromTop: 0)
|
||||
var size = (width: 0, height: 0)
|
||||
}
|
||||
|
||||
// We know:
|
||||
// - the number of claims
|
||||
// - the size and position of each claim
|
||||
// - the claim size and positions are all integers => using array cells to solve
|
||||
|
||||
// Read in data
|
||||
// parse data
|
||||
// find out the size of the sheet
|
||||
// lay down all the claims
|
||||
// count the overlapping cells
|
||||
class Slice {
|
||||
var fabric: [[Int]] = []
|
||||
var claims: [ElfSquare] = []
|
||||
var corruptedClaims: [Int : Bool] = [:] // build list of claims that overlap
|
||||
|
||||
|
||||
// Supply filename for input ex: '/home/peterr/AOC2018/Sources/AOC2018/data/day03.txt'
|
||||
init(withFile filename: String) {
|
||||
let slices = Tools.readFile(fromPath: filename)
|
||||
var sliceArray = slices.components(separatedBy: "\n")
|
||||
// This gurd statement is just an excuse to use guard
|
||||
// I'm assuming the last string is an empty string, if not DON'T remove the last string
|
||||
guard let lastStr = sliceArray.last, lastStr.count == 0 else { return }
|
||||
sliceArray.removeLast() // empty string
|
||||
parseData(withSlices: sliceArray)
|
||||
}
|
||||
|
||||
// Supply test data in the form of a String
|
||||
init(withString slices: String) {
|
||||
let sliceArray = slices.components(separatedBy: "\n")
|
||||
parseData(withSlices: sliceArray)
|
||||
}
|
||||
|
||||
func parseData(withSlices sliceArray: [String]) {
|
||||
|
||||
func getTuple(from tupleString: String, withSeparator sep: String) -> (Int, Int) {
|
||||
var retVal = (-1, -1)
|
||||
let elements = tupleString.components(separatedBy: sep)
|
||||
if (elements.count > 1) {
|
||||
let first = Int(elements[0]) ?? -1
|
||||
let second = Int(elements[1]) ?? -1
|
||||
retVal = (first, second)
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
// #1 @ 1,3: 4x4
|
||||
for line in sliceArray {
|
||||
var claim = line
|
||||
var square = ElfSquare()
|
||||
// remove all spaces and convert delimeters to ':'
|
||||
claim.removeFirst()
|
||||
claim = claim.replacingOccurrences(of: " ", with: "")
|
||||
claim = claim.replacingOccurrences(of: "@", with: ":")
|
||||
var parts = claim.components(separatedBy: ":")
|
||||
square.ID = Int(parts[0]) ?? -1
|
||||
square.loc = getTuple(from: parts[1], withSeparator: ",")
|
||||
square.size = getTuple(from: parts[2], withSeparator: "x")
|
||||
claims.append(square)
|
||||
corruptedClaims[square.ID] = false
|
||||
}
|
||||
}
|
||||
|
||||
// find out the size of the sheet
|
||||
func getFabricSize() -> (width: Int, height: Int) {
|
||||
var retVal = (-1, -1)
|
||||
var maxHeight = 0
|
||||
var maxWidth = 0
|
||||
for claim in claims {
|
||||
let height = claim.loc.fromTop + claim.size.height
|
||||
let width = claim.loc.fromLeft + claim.size.width
|
||||
maxHeight = max(maxHeight, height)
|
||||
maxWidth = max(maxWidth, width)
|
||||
}
|
||||
maxHeight += 1
|
||||
maxWidth += 1
|
||||
retVal = (maxWidth, maxHeight)
|
||||
fabric = Array(repeating: Array(repeating: 0, count: maxWidth), count: maxHeight)
|
||||
return retVal
|
||||
}
|
||||
|
||||
// lay down all the claims
|
||||
func apply(claim: ElfSquare) {
|
||||
for j in claim.loc.fromTop..<(claim.loc.fromTop+claim.size.height) {
|
||||
for i in claim.loc.fromLeft..<(claim.loc.fromLeft+claim.size.width) {
|
||||
if fabric[j][i] != 0 {
|
||||
if fabric[j][i] > 0 {
|
||||
corruptedClaims[fabric[j][i]] = true
|
||||
}
|
||||
corruptedClaims[claim.ID] = true
|
||||
fabric[j][i] = -1
|
||||
} else {
|
||||
fabric[j][i] = claim.ID
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// count the overlapping cells
|
||||
func countOverlappingClaims() -> Int {
|
||||
var retVal = 0
|
||||
if fabric.count == 0 {
|
||||
_ = getFabricSize()
|
||||
}
|
||||
for claim in claims {
|
||||
apply(claim: claim)
|
||||
}
|
||||
for row in fabric {
|
||||
retVal += row.filter { $0 == -1 }.count
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
// Find the one cell that does not overlap
|
||||
func findUncorruptedClaim() -> Int {
|
||||
return corruptedClaims.filter{ $0.value == false }.keys.first ?? -1
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Day03: AOCDay {
|
||||
lazy var tests: (() -> ()) = day03Tests
|
||||
lazy var final: (() -> ()) = day03Final
|
||||
|
||||
let testSample = """
|
||||
#1 @ 1,3: 4x4
|
||||
#2 @ 3,1: 4x4
|
||||
#3 @ 5,5: 2x2
|
||||
"""
|
||||
|
||||
func testDisplaySample(fabric: [[Int]]) {
|
||||
for j in 0..<fabric.count {
|
||||
for i in 0..<fabric[j].count {
|
||||
if fabric[j][i] == 0 {
|
||||
print(".", terminator: " ")
|
||||
} else if fabric[j][i] == -1 {
|
||||
print("X", terminator: " ")
|
||||
} else {
|
||||
print("\(fabric[j][i])", terminator: " ")
|
||||
}
|
||||
}
|
||||
print("")
|
||||
}
|
||||
}
|
||||
|
||||
// Read in data
|
||||
func testSliceInitWithString() {
|
||||
let slice = Slice(withString: testSample)
|
||||
XCTAssertEqual(test: "testSliceInitWithString [1].ID", withExpression: (slice.claims[1].ID == 2))
|
||||
XCTAssertEqual(test: "testSliceInitWithString [1].loc", withExpression: (slice.claims[1].loc == (3,1)))
|
||||
XCTAssertEqual(test: "testSliceInitWithString [1].size", withExpression: (slice.claims[1].size == (4, 4)))
|
||||
}
|
||||
|
||||
// Read in data
|
||||
func testSliceInitWithFile() {
|
||||
let slice = Slice(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day03.txt")
|
||||
XCTAssertEqual(test: "testSliceInitWithFile [699].ID", withExpression: (slice.claims[699].ID == 700))
|
||||
XCTAssertEqual(test: "testSliceInitWithFile [700].loc", withExpression: (slice.claims[700].loc == (821, 673)))
|
||||
XCTAssertEqual(test: "testSliceInitWithFile [701].size", withExpression: (slice.claims[701].size == (13, 20)))
|
||||
}
|
||||
|
||||
// find out the size of the sheet
|
||||
func testGetFabricSize() {
|
||||
let slice = Slice(withString: testSample)
|
||||
let dims = slice.getFabricSize()
|
||||
XCTAssertEqual(test: "testGetFabricSize", withExpression: (dims == (8, 8)))
|
||||
}
|
||||
|
||||
// lay down all the claims
|
||||
func testApplyClaim() {
|
||||
let slice = Slice(withString: testSample)
|
||||
_ = slice.getFabricSize()
|
||||
testDisplaySample(fabric: slice.fabric)
|
||||
slice.apply(claim: slice.claims[0])
|
||||
print("")
|
||||
testDisplaySample(fabric: slice.fabric)
|
||||
slice.apply(claim: slice.claims[1])
|
||||
print("")
|
||||
testDisplaySample(fabric: slice.fabric)
|
||||
slice.apply(claim: slice.claims[2])
|
||||
print("")
|
||||
testDisplaySample(fabric: slice.fabric)
|
||||
}
|
||||
|
||||
// count the overlapping cells
|
||||
func testCountOverlappingFrames() {
|
||||
let slice = Slice(withString: testSample)
|
||||
let overlapArea = slice.countOverlappingClaims()
|
||||
XCTAssertEqual(test: "testCountOverlappingFrames", withExpression: (overlapArea == 4))
|
||||
}
|
||||
|
||||
func testFindUncorruptedClaim() {
|
||||
let slice = Slice(withString: testSample)
|
||||
_ = slice.countOverlappingClaims()
|
||||
let uncorruptedClaimID = slice.findUncorruptedClaim()
|
||||
XCTAssertEqual(test: "testFindUncorruptedClaim", withExpression: (uncorruptedClaimID == 3))
|
||||
}
|
||||
|
||||
func day03Tests() {
|
||||
testSliceInitWithString()
|
||||
testSliceInitWithFile()
|
||||
testGetFabricSize()
|
||||
testApplyClaim()
|
||||
testCountOverlappingFrames()
|
||||
testFindUncorruptedClaim()
|
||||
}
|
||||
|
||||
func day03Final() {
|
||||
let slice = Slice(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day03.txt")
|
||||
let overlapArea = slice.countOverlappingClaims()
|
||||
print("Answer to part 1 is: \(overlapArea)")
|
||||
print("Answer to part 2 is: \(slice.findUncorruptedClaim())")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,400 @@
|
||||
//
|
||||
// Advent of Code 2018 "Day 4: Repose Record"
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum Action {
|
||||
case startShift
|
||||
case sleep
|
||||
case wake
|
||||
case none
|
||||
}
|
||||
|
||||
struct Activity: Equatable, Comparable {
|
||||
var day = -1
|
||||
var minute = -1
|
||||
var sortKey = -1.0 // Cobination of day + minute/60
|
||||
var action = Action.none
|
||||
var id = -1
|
||||
|
||||
static func == (lhs: Activity, rhs: Activity) -> Bool {
|
||||
return (lhs.day == rhs.day) && (lhs.minute == rhs.minute) && (lhs.sortKey == rhs.sortKey) && (lhs.action == rhs.action) && (lhs.id == rhs.id)
|
||||
}
|
||||
|
||||
static func < (lhs: Activity, rhs: Activity) -> Bool {
|
||||
return lhs.sortKey < rhs.sortKey
|
||||
}
|
||||
}
|
||||
|
||||
// Make some assumptions based on the fact that there is only on guard on duty per night
|
||||
|
||||
// read in data
|
||||
// parse data to extract sleep times for each guard on each day
|
||||
// create guard sleep map
|
||||
// determine best guard with best minute
|
||||
// - find guard with most minutes asleep
|
||||
// - create histogram and determine which minute he has slept through the most
|
||||
class Repose {
|
||||
var scheduleArray: [String] = []
|
||||
var sleepMapForGuardID: [Int : [Int]] = [:] // dictionary of [id : Array of ints, one for each hour; increment if asleep]
|
||||
var activitiesForDay: [Int : [Activity]] = [:]
|
||||
|
||||
// Supply filename for input ex: '/home/peterr/AOC2018/Sources/AOC2018/data/day04.txt'
|
||||
init(withFile filename: String) {
|
||||
let schedule = Tools.readFile(fromPath: filename)
|
||||
scheduleArray = schedule.components(separatedBy: "\n")
|
||||
// This gurd statement is just an excuse to use guard
|
||||
// I'm assuming the last string is an empty string, if not DON'T remove the last string
|
||||
guard let lastStr = scheduleArray.last, lastStr.count == 0 else { return }
|
||||
scheduleArray.removeLast() // empty string
|
||||
}
|
||||
|
||||
// Supply test data in the form of a String
|
||||
init(withString schedule: String) {
|
||||
scheduleArray = schedule.components(separatedBy: "\n")
|
||||
}
|
||||
|
||||
// Needed this due to Guard starting day before midnight of the previous month (broke my simple day = month * 31 rule)
|
||||
static func increment(day: Int) -> Int {
|
||||
// there is a leap year every year divisible by four except for years which are both divisible by 100 and not divisible by 400.
|
||||
// Therefore, the year 2000 will be a leap year, but the years 1700, 1800, and 1900 were not.
|
||||
var retVal = 0
|
||||
let nDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
||||
// let leapnDays = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
||||
var myMonth = day / 31
|
||||
var myDay = day % 31
|
||||
if myDay == 0 {
|
||||
myDay = 31
|
||||
myMonth -= 1
|
||||
}
|
||||
if myDay == nDays[myMonth - 1] {
|
||||
retVal = (myMonth + 1) * 31 + 1
|
||||
} else {
|
||||
retVal = day + 1
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
static func parse(line: String) -> Activity {
|
||||
var retVal = Activity()
|
||||
|
||||
parseScope:
|
||||
if line.count > 0 {
|
||||
// Split line into time and action
|
||||
var parseString = line
|
||||
parseString.removeFirst()
|
||||
let splitStr = parseString.components(separatedBy: "]")
|
||||
guard splitStr.count > 1 else { break parseScope }
|
||||
let timedateSplit = splitStr[0].components(separatedBy: " ")
|
||||
guard timedateSplit.count > 1 else { break parseScope }
|
||||
let dateSplit = timedateSplit[0].components(separatedBy: "-")
|
||||
guard dateSplit.count > 2 else { break parseScope }
|
||||
let month = (Int(dateSplit[1]) ?? 0) * 31
|
||||
let date = Int(dateSplit[2]) ?? 0
|
||||
let day = month + date
|
||||
// Parse time into day and minutes
|
||||
let timeSplit = timedateSplit[1].components(separatedBy: ":")
|
||||
guard timeSplit.count > 1 else { break parseScope }
|
||||
guard let hour = Int(timeSplit[0]) else { break parseScope }
|
||||
guard let min = Int(timeSplit[1]) else { break parseScope }
|
||||
retVal.day = day
|
||||
retVal.minute = min
|
||||
if hour == 23 {
|
||||
retVal.day = Repose.increment(day: retVal.day) // Need to accomodate last day of the month
|
||||
retVal.minute = 0
|
||||
}
|
||||
retVal.sortKey = Double(retVal.day) + Double(retVal.minute) / 60.0
|
||||
// parse Action
|
||||
let actionStr = splitStr[1].suffix(splitStr[1].count - 7)
|
||||
switch actionStr {
|
||||
case "asleep" :
|
||||
retVal.action = Action.sleep
|
||||
case "up" :
|
||||
retVal.action = Action.wake
|
||||
default:
|
||||
retVal.action = Action.startShift
|
||||
var startShiftStr = actionStr
|
||||
startShiftStr.removeFirst()
|
||||
retVal.id = Int(startShiftStr.components(separatedBy: " ")[0]) ?? -1
|
||||
}
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func add(activity: Activity) {
|
||||
if activitiesForDay[activity.day] == nil {
|
||||
activitiesForDay[activity.day] = [activity]
|
||||
} else {
|
||||
activitiesForDay[activity.day]!.append(activity)
|
||||
}
|
||||
}
|
||||
|
||||
func addActivitiesIfNecessary() {
|
||||
if activitiesForDay.keys.count == 0 {
|
||||
for act in scheduleArray {
|
||||
add(activity: Repose.parse(line: act))
|
||||
}
|
||||
for day in activitiesForDay.keys {
|
||||
activitiesForDay[day]!.sort()
|
||||
sleepMapForGuardID[findID(forDay: day)] = Array(repeating: 0, count: 60)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func findID(forDay day: Int) -> Int {
|
||||
var retVal = -1
|
||||
addActivitiesIfNecessary()
|
||||
if let array = activitiesForDay[day] {
|
||||
retVal = array.filter { $0.id != -1 }[0].id
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func buildHistogram(forDay day: Int) -> [Int] {
|
||||
var retVal = Array(repeating: 0, count: 60)
|
||||
addActivitiesIfNecessary()
|
||||
if let array = activitiesForDay[day] {
|
||||
var startSleep = 0
|
||||
var endSleep = 0
|
||||
for activity in array {
|
||||
if activity.action == Action.sleep {
|
||||
startSleep = activity.minute
|
||||
} else if activity.action == Action.wake {
|
||||
endSleep = activity.minute
|
||||
for min in startSleep..<endSleep {
|
||||
retVal[min] = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func add(histogram: [Int], toID id: Int) {
|
||||
guard var array = sleepMapForGuardID[id] else { return }
|
||||
guard array.count == 60 else { return }
|
||||
guard histogram.count == 60 else { return }
|
||||
for i in 0..<60 {
|
||||
array[i] = array[i] + histogram[i]
|
||||
}
|
||||
sleepMapForGuardID[id] = array
|
||||
}
|
||||
|
||||
// Sum all the minutes slept, retrun the total and the minute of most sleeps
|
||||
func sumMinutes(forID id: Int) -> (total: Int, maxMinute: Int, maxMinuteVal: Int) {
|
||||
var retVal = (total: 0, maxMinute: -1, maxMinuteVal: -1)
|
||||
guard var array = sleepMapForGuardID[id] else { return retVal }
|
||||
guard array.count == 60 else { return retVal }
|
||||
for i in 0..<60 {
|
||||
retVal.total += array[i]
|
||||
}
|
||||
retVal.maxMinuteVal = array.max() ?? 1
|
||||
retVal.maxMinute = array.firstIndex(of: retVal.maxMinuteVal) ?? 0
|
||||
return retVal
|
||||
}
|
||||
|
||||
func findGuard(forPart1 part1: Bool) -> (id: Int, minute: Int) {
|
||||
var retVal = (id: 0, minute: -1)
|
||||
addActivitiesIfNecessary()
|
||||
for day in activitiesForDay.keys {
|
||||
let hist = buildHistogram(forDay: day)
|
||||
add(histogram: hist, toID: findID(forDay: day))
|
||||
}
|
||||
var maxTime = 0
|
||||
for id in sleepMapForGuardID.keys {
|
||||
let stats = sumMinutes(forID: id)
|
||||
let maxForPart = part1 ? stats.total : stats.maxMinuteVal
|
||||
if maxForPart > maxTime {
|
||||
maxTime = maxForPart
|
||||
retVal.minute = stats.maxMinute
|
||||
retVal.id = id
|
||||
}
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
}
|
||||
|
||||
// Need a state-machine
|
||||
// - start shift
|
||||
// - sleep
|
||||
// - wake
|
||||
// Date ID Minute
|
||||
// 000000000011111111112222222222333333333344444444445555555555
|
||||
// 012345678901234567890123456789012345678901234567890123456789
|
||||
// 11-01 #10 .....####################.....#########################.....
|
||||
// 11-03 #10 ........................#####...............................
|
||||
// #10 0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0
|
||||
// 11-02 #99 ........................................##########..........
|
||||
// 11-04 #99 ....................................##########..............
|
||||
// 11-05 #99 .............................................##########.....
|
||||
// #99 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,2,3,2,2,2,2,1,1,1,1,1,0,0,0,0,0
|
||||
|
||||
class Day04: AOCDay {
|
||||
lazy var tests: (() -> ()) = day04Tests
|
||||
lazy var final: (() -> ()) = day04Final
|
||||
|
||||
let testData = """
|
||||
[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
|
||||
[1518-11-03 00:05] Guard #10 begins shift
|
||||
[1518-11-03 00:24] falls asleep
|
||||
[1518-11-03 00:29] wakes up
|
||||
[1518-11-04 00:02] Guard #99 begins shift
|
||||
[1518-11-04 00:36] falls asleep
|
||||
[1518-11-04 00:46] wakes up
|
||||
[1518-11-05 00:03] Guard #99 begins shift
|
||||
[1518-11-05 00:45] falls asleep
|
||||
[1518-11-05 00:55] wakes up
|
||||
"""
|
||||
|
||||
let mapNum10 = [0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0]
|
||||
let mapNum99 = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,2,3,2,2,2,2,1,1,1,1,1,0,0,0,0,0]
|
||||
let day342 = [0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0]
|
||||
let day344 = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
|
||||
|
||||
func testIncrementDay() {
|
||||
var testDay = Repose.increment(day: 62)
|
||||
XCTAssertEqual(test: "testIncrementDay end-of-month 1", withExpression: (testDay == 2*31 + 1))
|
||||
testDay = Repose.increment(day:90)
|
||||
XCTAssertEqual(test: "testIncrementDay end-of-month 2", withExpression: (testDay == 3*31 + 1))
|
||||
testDay = Repose.increment(day: 124)
|
||||
XCTAssertEqual(test: "testIncrementDay end-of-month 3", withExpression: (testDay == 4*31 + 1))
|
||||
testDay = Repose.increment(day: 154)
|
||||
XCTAssertEqual(test: "testIncrementDay end-of-month 4", withExpression: (testDay == 5*31 + 1))
|
||||
testDay = Repose.increment(day: 186)
|
||||
XCTAssertEqual(test: "testIncrementDay end-of-month 5", withExpression: (testDay == 6*31 + 1))
|
||||
testDay = Repose.increment(day: 216)
|
||||
XCTAssertEqual(test: "testIncrementDay end-of-month 6", withExpression: (testDay == 7*31 + 1))
|
||||
testDay = Repose.increment(day: 248)
|
||||
XCTAssertEqual(test: "testIncrementDay end-of-month 7", withExpression: (testDay == 8*31 + 1))
|
||||
testDay = Repose.increment(day: 279)
|
||||
XCTAssertEqual(test: "testIncrementDay end-of-month 8", withExpression: (testDay == 9*31 + 1))
|
||||
testDay = Repose.increment(day: 309)
|
||||
XCTAssertEqual(test: "testIncrementDay end-of-month 9", withExpression: (testDay == 10*31 + 1))
|
||||
testDay = Repose.increment(day: 341)
|
||||
XCTAssertEqual(test: "testIncrementDay end-of-month 10", withExpression: (testDay == 11*31 + 1))
|
||||
testDay = Repose.increment(day: 371)
|
||||
XCTAssertEqual(test: "testIncrementDay end-of-month 11", withExpression: (testDay == 12*31 + 1))
|
||||
testDay = Repose.increment(day: 403)
|
||||
XCTAssertEqual(test: "testIncrementDay end-of-month 12", withExpression: (testDay == 13*31 + 1))
|
||||
}
|
||||
|
||||
func testPasrseLine() {
|
||||
var response = Repose.parse(line: "")
|
||||
XCTAssertEqual(test: "testPasrseLine empty", withExpression: (response.minute == -1))
|
||||
let repo = Repose(withString: testData)
|
||||
response = Repose.parse(line: repo.scheduleArray[0])
|
||||
XCTAssertEqual(test: "testPasrseLine begin", withExpression: (response == Activity(day: 341+1, minute: 0, sortKey: 342.0, action: Action.startShift, id: 10)))
|
||||
response = Repose.parse(line: repo.scheduleArray[1])
|
||||
XCTAssertEqual(test: "testPasrseLine first asleep", withExpression: (response == Activity(day: 341+1, minute: 5, sortKey: 342.0 + 5.0/60.0, action: Action.sleep, id: -1)))
|
||||
response = Repose.parse(line: repo.scheduleArray[2])
|
||||
XCTAssertEqual(test: "testPasrseLine first wake up", withExpression: (response == Activity(day: 341+1, minute: 25, sortKey: 342.0 + 25.0/60.0, action: Action.wake, id: -1)))
|
||||
response = Repose.parse(line: repo.scheduleArray[3])
|
||||
XCTAssertEqual(test: "testPasrseLine second alseep", withExpression: (response == Activity(day: 341+1, minute: 30, sortKey: 342.0 + 0.5, action: Action.sleep, id: -1)))
|
||||
response = Repose.parse(line: repo.scheduleArray[4])
|
||||
XCTAssertEqual(test: "testPasrseLine second wake up", withExpression: (response == Activity(day: 341+1, minute: 55, sortKey: 342.0 + 55.0/60.0, action: Action.wake, id: -1)))
|
||||
response = Repose.parse(line: repo.scheduleArray[5])
|
||||
XCTAssertEqual(test: "testPasrseLine new guard", withExpression: (response == Activity(day: 341+2, minute: 0, sortKey: 343.0, action: Action.startShift, id: 99)))
|
||||
response = Repose.parse(line: repo.scheduleArray[6])
|
||||
XCTAssertEqual(test: "testPasrseLine alseep", withExpression: (response == Activity(day: 341+2, minute: 40, sortKey: 343.0 + 2.0/3.0, action: Action.sleep, id: -1)))
|
||||
response = Repose.parse(line: repo.scheduleArray[7])
|
||||
XCTAssertEqual(test: "testPasrseLine wake up", withExpression: (response == Activity(day: 341+2, minute: 50, sortKey: 343.0 + 50.0/60.0, action: Action.wake, id: -1)))
|
||||
}
|
||||
|
||||
func testAddActivity() {
|
||||
let repo = Repose(withString: testData)
|
||||
for act in repo.scheduleArray {
|
||||
repo.add(activity: Repose.parse(line: act))
|
||||
}
|
||||
XCTAssertEqual(test: "testAddActivity number of days", withExpression: (repo.activitiesForDay.keys.count == 5))
|
||||
var count = repo.activitiesForDay[342]?.count ?? 0
|
||||
XCTAssertEqual(test: "testAddActivity activies day 1", withExpression: (count == 5))
|
||||
count = repo.activitiesForDay[343]?.count ?? 0
|
||||
XCTAssertEqual(test: "testAddActivity activies day 2", withExpression: (count == 3))
|
||||
count = repo.activitiesForDay[344]?.count ?? 0
|
||||
XCTAssertEqual(test: "testAddActivity activies day 3", withExpression: (count == 3))
|
||||
}
|
||||
|
||||
func testFindIDForDay() {
|
||||
let repo = Repose(withString: testData)
|
||||
var id = repo.findID(forDay: 342)
|
||||
XCTAssertEqual(test: "testFindIDForDay activies day 342", withExpression: (id == 10))
|
||||
id = repo.findID(forDay: 343)
|
||||
XCTAssertEqual(test: "testFindIDForDay activies day 343", withExpression: (id == 99))
|
||||
id = repo.findID(forDay: 344)
|
||||
XCTAssertEqual(test: "testFindIDForDay activies day 344", withExpression: (id == 10))
|
||||
id = repo.findID(forDay: 345)
|
||||
XCTAssertEqual(test: "testFindIDForDay activies day 345", withExpression: (id == 99))
|
||||
id = repo.findID(forDay: 346)
|
||||
XCTAssertEqual(test: "testFindIDForDay activies day 346", withExpression: (id == 99))
|
||||
}
|
||||
|
||||
func testBuildHistogram() {
|
||||
let repo = Repose(withString: testData)
|
||||
var hist = repo.buildHistogram(forDay: 342)
|
||||
XCTAssertEqual(test: "testBuildHistogram activies day 342", withExpression: (hist == day342))
|
||||
hist = repo.buildHistogram(forDay: 344)
|
||||
XCTAssertEqual(test: "testBuildHistogram activies day 344", withExpression: (hist == day344))
|
||||
}
|
||||
|
||||
func testAddHistogram() {
|
||||
let repo = Repose(withString: testData)
|
||||
repo.addActivitiesIfNecessary()
|
||||
for day in repo.activitiesForDay.keys {
|
||||
let hist = repo.buildHistogram(forDay: day)
|
||||
repo.add(histogram: hist, toID: repo.findID(forDay: day))
|
||||
}
|
||||
guard let histID10 = repo.sleepMapForGuardID[10] else { return }
|
||||
guard let histID99 = repo.sleepMapForGuardID[99] else { return }
|
||||
XCTAssertEqual(test: "testAddHistogram id 10", withExpression: (histID10 == mapNum10))
|
||||
XCTAssertEqual(test: "testAddHistogram id 99", withExpression: (histID99 == mapNum99))
|
||||
}
|
||||
|
||||
func testSumMinutes() {
|
||||
let repo = Repose(withString: testData)
|
||||
repo.addActivitiesIfNecessary()
|
||||
for day in repo.activitiesForDay.keys {
|
||||
let hist = repo.buildHistogram(forDay: day)
|
||||
repo.add(histogram: hist, toID: repo.findID(forDay: day))
|
||||
}
|
||||
var tuple = repo.sumMinutes(forID: 10)
|
||||
let passTest = (tuple.total == 50) && (tuple.maxMinute == 24)
|
||||
XCTAssertEqual(test: "testSumMinutes id 10", withExpression: passTest)
|
||||
tuple = repo.sumMinutes(forID: 99)
|
||||
XCTAssertEqual(test: "testSumMinutes id 99", withExpression: (tuple == (30, 45, 3)))
|
||||
}
|
||||
|
||||
func testFindGuard() {
|
||||
let repo = Repose(withString: testData)
|
||||
var answer = repo.findGuard(forPart1: true)
|
||||
XCTAssertEqual(test: "testFindGuard Part 1", withExpression: (answer == (10, 24)))
|
||||
answer = repo.findGuard(forPart1: false)
|
||||
XCTAssertEqual(test: "testFindGuard Part 2", withExpression: (answer == (99, 45)))
|
||||
}
|
||||
|
||||
func day04Tests() {
|
||||
testIncrementDay()
|
||||
testPasrseLine()
|
||||
testAddActivity()
|
||||
testFindIDForDay()
|
||||
testBuildHistogram()
|
||||
testAddHistogram()
|
||||
testSumMinutes()
|
||||
testFindGuard()
|
||||
}
|
||||
|
||||
func day04Final() {
|
||||
let repo = Repose(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day04.txt")
|
||||
var answer = repo.findGuard(forPart1: true)
|
||||
print("Answer to part 1 is: \(answer.id * answer.minute)")
|
||||
answer = repo.findGuard(forPart1: false)
|
||||
print("Answer to part 2 is: \(answer.id * answer.minute)")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
//
|
||||
// Advent of Code 2018 "Day 5: Alchemical Reduction"
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class Reduction {
|
||||
var polymer: [Character] = []
|
||||
var acc: [Character] = []
|
||||
|
||||
// Supply filename for input ex: '/home/peterr/AOC2018/Sources/AOC2018/data/day05.txt'
|
||||
init(withFile filename: String) {
|
||||
var polymerString = Tools.readFile(fromPath: filename)
|
||||
// This gurd statement is just an excuse to use guard
|
||||
// I'm assuming the last string is an empty string, if not DON'T remove the last string
|
||||
guard polymerString.count > 0 else { return }
|
||||
polymerString.removeLast() // new-line
|
||||
polymer = Array(polymerString)
|
||||
acc = Array(repeating: " ", count: polymer.count)
|
||||
}
|
||||
|
||||
// Supply test data in the form of a String
|
||||
init(withString poly: String) {
|
||||
polymer = Array(poly)
|
||||
acc = Array(repeating: " ", count: polymer.count)
|
||||
}
|
||||
|
||||
func reducer() {
|
||||
var aIdx = 0
|
||||
acc[aIdx] = polymer[0]
|
||||
for index in 1..<polymer.count {
|
||||
if (aIdx > -1 && acc[aIdx] != polymer[index]) && (String(acc[aIdx]).lowercased() == String(polymer[index]).lowercased()) {
|
||||
acc[aIdx] = " "
|
||||
aIdx -= 1
|
||||
} else {
|
||||
aIdx += 1
|
||||
acc[aIdx] = polymer[index]
|
||||
}
|
||||
}
|
||||
polymer = acc.filter {$0 != " "}
|
||||
}
|
||||
|
||||
func findSmallestFullyReactedAndRemovedPolymer() -> Int {
|
||||
let start = Unicode.Scalar("a").value
|
||||
let end = Unicode.Scalar("z").value
|
||||
let polyCopy = polymer
|
||||
var minLen = polymer.count
|
||||
for i in start...end {
|
||||
polymer = polyCopy
|
||||
acc = Array(repeating: " ", count: polymer.count)
|
||||
if let type = Unicode.Scalar(i) {
|
||||
let unit = Character(type)
|
||||
let upperUnit = Character(String(unit).uppercased())
|
||||
polymer = polymer.filter { $0 != unit && $0 != upperUnit }
|
||||
reducer()
|
||||
minLen = min(minLen, polymer.count)
|
||||
}
|
||||
}
|
||||
return minLen
|
||||
}
|
||||
}
|
||||
|
||||
class Day05: AOCDay {
|
||||
lazy var tests: (() -> ()) = day05Tests
|
||||
lazy var final: (() -> ()) = day05Final
|
||||
|
||||
// In aA, a and A react, leaving nothing behind.
|
||||
// In abBA, bB destroys itself, leaving aA. As above, this then destroys itself, leaving nothing.
|
||||
// In abAB, no two adjacent units are of the same type, and so nothing happens.
|
||||
// In aabAAB, even though aa and AA are of the same type, their polarities match, and so nothing happens.
|
||||
|
||||
let testData = "dabAcCaCBAcCcaDA"
|
||||
|
||||
func testReductionInit() {
|
||||
let testArray = Array(testData)
|
||||
var reduc = Reduction(withString: testData)
|
||||
XCTAssertEqual(test: "testReductionInit with String", withExpression: (reduc.polymer == testArray))
|
||||
reduc = Reduction(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day05.txt")
|
||||
XCTAssertEqual(test: "testReductionInit with File", withExpression: (reduc.polymer.last == "Y"))
|
||||
}
|
||||
|
||||
func testReducePolymer() {
|
||||
var reduc = Reduction(withString: "aA")
|
||||
reduc.reducer()
|
||||
XCTAssertEqual(test: "testReducePolymer", withExpression: (String(reduc.polymer) == ""))
|
||||
reduc = Reduction(withString: "abBA")
|
||||
reduc.reducer()
|
||||
XCTAssertEqual(test: "testReducePolymer", withExpression: (String(reduc.polymer) == ""))
|
||||
reduc = Reduction(withString: "abAB")
|
||||
reduc.reducer()
|
||||
XCTAssertEqual(test: "testReducePolymer", withExpression: (String(reduc.polymer) == "abAB"))
|
||||
reduc = Reduction(withString: "aabAAB")
|
||||
reduc.reducer()
|
||||
XCTAssertEqual(test: "testReducePolymer", withExpression: (String(reduc.polymer) == "aabAAB"))
|
||||
reduc = Reduction(withString: testData)
|
||||
reduc.reducer()
|
||||
XCTAssertEqual(test: "testReducePolymer", withExpression: (String(reduc.polymer) == "dabCBAcaDA"))
|
||||
}
|
||||
|
||||
func testRemoveUnit() {
|
||||
var reduc = Reduction(withString: testData)
|
||||
reduc.polymer = reduc.polymer.filter { $0 != "a" && $0 != "A" }
|
||||
XCTAssertEqual(test: "testRemoveOneType", withExpression: (String(reduc.polymer) == "dbcCCBcCcD"))
|
||||
reduc = Reduction(withString: testData)
|
||||
reduc.polymer = reduc.polymer.filter { $0 != "b" && $0 != "B" }
|
||||
XCTAssertEqual(test: "testRemoveOneType", withExpression: (String(reduc.polymer) == "daAcCaCAcCcaDA"))
|
||||
reduc = Reduction(withString: testData)
|
||||
reduc.polymer = reduc.polymer.filter { $0 != "c" && $0 != "C" }
|
||||
XCTAssertEqual(test: "testRemoveOneType", withExpression: (String(reduc.polymer) == "dabAaBAaDA"))
|
||||
reduc = Reduction(withString: testData)
|
||||
reduc.polymer = reduc.polymer.filter { $0 != "d" && $0 != "D" }
|
||||
XCTAssertEqual(test: "testRemoveOneType", withExpression: (String(reduc.polymer) == "abAcCaCBAcCcaA"))
|
||||
}
|
||||
|
||||
func testRemoveAndReact() {
|
||||
var reduc = Reduction(withString: testData)
|
||||
reduc.polymer = reduc.polymer.filter { $0 != "a" && $0 != "A" }
|
||||
reduc.reducer()
|
||||
XCTAssertEqual(test: "testRemoveAndReact a", withExpression: (String(reduc.polymer) == "dbCBcD"))
|
||||
reduc = Reduction(withString: testData)
|
||||
reduc.polymer = reduc.polymer.filter { $0 != "b" && $0 != "B" }
|
||||
reduc.reducer()
|
||||
XCTAssertEqual(test: "testRemoveAndReact b", withExpression: (String(reduc.polymer) == "daCAcaDA"))
|
||||
reduc = Reduction(withString: testData)
|
||||
reduc.polymer = reduc.polymer.filter { $0 != "c" && $0 != "C" }
|
||||
reduc.reducer()
|
||||
XCTAssertEqual(test: "testRemoveAndReact c", withExpression: (String(reduc.polymer) == "daDA"))
|
||||
reduc = Reduction(withString: testData)
|
||||
reduc.polymer = reduc.polymer.filter { $0 != "d" && $0 != "D" }
|
||||
reduc.reducer()
|
||||
XCTAssertEqual(test: "testRemoveAndReact d", withExpression: (String(reduc.polymer) == "abCBAc"))
|
||||
}
|
||||
|
||||
func testFindSmallestFullyReactedAndRemovedPolymer() {
|
||||
let reduc = Reduction(withString: testData)
|
||||
let answer = reduc.findSmallestFullyReactedAndRemovedPolymer()
|
||||
XCTAssertEqual(test: "testFindSmallestFullyReactedAndRemovedPolymer", withExpression: (answer == 4))
|
||||
}
|
||||
|
||||
func day05Tests() {
|
||||
testReductionInit()
|
||||
testReducePolymer()
|
||||
testRemoveUnit()
|
||||
testRemoveAndReact()
|
||||
testFindSmallestFullyReactedAndRemovedPolymer()
|
||||
}
|
||||
|
||||
func day05Final() {
|
||||
var reduc = Reduction(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day05.txt")
|
||||
reduc.reducer()
|
||||
print("Answer to part 1 is: \(reduc.polymer.count)")
|
||||
reduc = Reduction(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day05.txt")
|
||||
let answer = reduc.findSmallestFullyReactedAndRemovedPolymer()
|
||||
print("Answer to part 2 is: \(answer)")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,288 @@
|
||||
//
|
||||
// Advent of Code 2018 "Day 6: Chronal Coordinates"
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class Coordinates {
|
||||
var points: [GridPoint] = []
|
||||
var dimensions: GridPoint
|
||||
|
||||
init(withString str: String) {
|
||||
var maxX = 0
|
||||
var maxY = 0
|
||||
dimensions = GridPoint(X: 0, Y: 0)
|
||||
let coordStrArray = str.components(separatedBy: "\n")
|
||||
for elem in coordStrArray {
|
||||
let coord = elem.components(separatedBy: ", ")
|
||||
guard coord.count > 1 else { return }
|
||||
guard let x = Int(coord[0]), let y = Int(coord[1]) else { return }
|
||||
points.append(GridPoint(X: x, Y: y))
|
||||
maxX = max(maxX, x)
|
||||
maxY = max(maxY, y)
|
||||
}
|
||||
dimensions = GridPoint(X: maxX+1, Y: maxY)
|
||||
}
|
||||
|
||||
func distance(from: GridPoint, to: GridPoint) -> Int {
|
||||
let retVal = abs(from.X - to.X) + abs(from.Y - to.Y)
|
||||
return retVal
|
||||
}
|
||||
|
||||
// Given any gridpoint, find the LocPoint with the min distance to it (returned as Int (index))
|
||||
func findLocWithMinDistance(toPoint measurePt: GridPoint) -> (dist: Int, index: Int) {
|
||||
var minDist = dimensions.X + dimensions.Y // max distance
|
||||
var minIndex = 0
|
||||
var dist: [Int: Int] = [:]
|
||||
for locIndex in 0..<points.count {
|
||||
dist[locIndex] = distance(from: points[locIndex], to: measurePt)
|
||||
if dist[locIndex] ?? -1 < minDist {
|
||||
minDist = dist[locIndex] ?? -1
|
||||
minIndex = locIndex
|
||||
}
|
||||
}
|
||||
let duplicate = dist.filter { $0.value == minDist }.count > 1
|
||||
return (dist: duplicate ? -1 : minDist, index: minIndex)
|
||||
}
|
||||
|
||||
// Given any gridpoint, find the LocPoint with the min distance to it (returned as Int (index))
|
||||
func findSumOfAllDistances(toPoint measurePt: GridPoint) -> Int {
|
||||
var sum = 0
|
||||
for locIndex in 0..<points.count {
|
||||
sum += distance(from: points[locIndex], to: measurePt)
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
// Fill out the grid
|
||||
func fillGridWithMinDistIndicies() -> [Int] {
|
||||
var retVal: [Int] = []
|
||||
for j in 0...dimensions.Y {
|
||||
for i in 0...dimensions.X {
|
||||
let index = findLocWithMinDistance(toPoint: GridPoint(X: i, Y: j))
|
||||
if index.dist < 0 {
|
||||
retVal.append(-1) // indicate duplicate
|
||||
} else {
|
||||
retVal.append(index.index)
|
||||
}
|
||||
}
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
// Fill out the grid
|
||||
func fillGridWithSumLessThan(value nearestSum: Int) -> [Bool] {
|
||||
var retVal: [Bool] = []
|
||||
for j in 0...dimensions.Y {
|
||||
for i in 0...dimensions.X {
|
||||
retVal.append(findSumOfAllDistances(toPoint: GridPoint(X: i, Y: j)) < nearestSum)
|
||||
}
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func solveForPart1(print printMap: Bool) -> Int {
|
||||
var map = fillGridWithMinDistIndicies()
|
||||
var infinite: [Int : Int] = [:]
|
||||
let maxX = dimensions.X
|
||||
let maxY = dimensions.Y
|
||||
for j in 0...dimensions.Y {
|
||||
for i in 0...dimensions.X {
|
||||
let idx = j * (dimensions.X + 1) + i
|
||||
if i == 0 || j == 0 || i == maxX || j == maxY && infinite[idx] == nil {
|
||||
infinite[map[idx]] = 1
|
||||
}
|
||||
if printMap {
|
||||
if map[idx] < 0 {
|
||||
print("..", terminator: "")
|
||||
} else {
|
||||
print(NSString(format:"%2d", map[idx]), terminator: "")
|
||||
}
|
||||
}
|
||||
}
|
||||
if printMap { print("") }
|
||||
}
|
||||
if printMap { print("infinite = \(infinite)") }
|
||||
var maxArea = 0
|
||||
for locIdx in 0..<points.count {
|
||||
if infinite[locIdx] == nil {
|
||||
let area = map.filter { $0 == locIdx }.count
|
||||
maxArea = max(maxArea, area)
|
||||
}
|
||||
}
|
||||
return maxArea
|
||||
}
|
||||
|
||||
func solveForPart2(print printMap: Bool, withValue nearestSum: Int) -> Int {
|
||||
let map = fillGridWithSumLessThan(value: nearestSum)
|
||||
for j in 0...dimensions.Y {
|
||||
for i in 0...dimensions.X {
|
||||
let idx = j * (dimensions.X + 1) + i
|
||||
if printMap {
|
||||
if map[idx] {
|
||||
print("#", terminator: "")
|
||||
} else {
|
||||
print(".", terminator: "")
|
||||
}
|
||||
}
|
||||
}
|
||||
if printMap { print("") }
|
||||
}
|
||||
return map.filter { $0 == true }.count
|
||||
}
|
||||
}
|
||||
|
||||
class Day06: AOCDay {
|
||||
lazy var tests: (() -> ()) = day06Tests
|
||||
lazy var final: (() -> ()) = day06Final
|
||||
|
||||
let testData = """
|
||||
1, 1
|
||||
1, 6
|
||||
8, 3
|
||||
3, 4
|
||||
5, 5
|
||||
8, 9
|
||||
"""
|
||||
|
||||
func printGrid() {
|
||||
let coor = Coordinates(withString: testData)
|
||||
for j in 0...coor.dimensions.Y {
|
||||
for i in 0...coor.dimensions.X {
|
||||
if let index = coor.points.firstIndex(of: GridPoint(X: i, Y: j)) {
|
||||
print(" \(index) ", terminator: "")
|
||||
} else {
|
||||
print(" . ", terminator: "")
|
||||
}
|
||||
}
|
||||
print("")
|
||||
}
|
||||
print("")
|
||||
}
|
||||
|
||||
func testCoordinatesInit() {
|
||||
let coor = Coordinates(withString: testData)
|
||||
guard coor.points.count == 6 else {
|
||||
XCTAssertEqual(test: "testCoordinatesInit count", withExpression: (false))
|
||||
return
|
||||
}
|
||||
XCTAssertEqual(test: "testCoordinatesInit A", withExpression: (coor.points[0] == GridPoint(X: 1, Y: 1)))
|
||||
XCTAssertEqual(test: "testCoordinatesInit D", withExpression: (coor.points[3] == GridPoint(X: 3, Y: 4)))
|
||||
XCTAssertEqual(test: "testCoordinatesInit F", withExpression: (coor.points[5] == GridPoint(X: 8, Y: 9)))
|
||||
}
|
||||
|
||||
func testDistanceAtoAll() {
|
||||
let coor = Coordinates(withString: testData)
|
||||
guard coor.points.count == 6 else {
|
||||
XCTAssertEqual(test: "testDistanceAtoAll count", withExpression: (false))
|
||||
return
|
||||
}
|
||||
var dist = coor.distance(from: coor.points[0], to: coor.points[1])
|
||||
XCTAssertEqual(test: "testDistanceAtoAll A to B", withExpression: (dist == 5))
|
||||
dist = coor.distance(from: coor.points[0], to: coor.points[2])
|
||||
XCTAssertEqual(test: "testDistanceAtoAll A to C", withExpression: (dist == 9))
|
||||
dist = coor.distance(from: coor.points[0], to: coor.points[3])
|
||||
XCTAssertEqual(test: "testDistanceAtoAll A to D", withExpression: (dist == 5))
|
||||
dist = coor.distance(from: coor.points[0], to: coor.points[4])
|
||||
XCTAssertEqual(test: "testDistanceAtoAll A to E", withExpression: (dist == 8))
|
||||
dist = coor.distance(from: coor.points[0], to: coor.points[5])
|
||||
XCTAssertEqual(test: "testDistanceAtoAll A to F", withExpression: (dist == 15))
|
||||
}
|
||||
|
||||
func testFindLocWithMinDistance() {
|
||||
let coor = Coordinates(withString: testData)
|
||||
var nearest = coor.findLocWithMinDistance(toPoint: GridPoint(X: 0, Y: 0))
|
||||
XCTAssertEqual(test: "testFindLocWithMinDistance (0, 0)", withExpression: (nearest.index == 0))
|
||||
nearest = coor.findLocWithMinDistance(toPoint: GridPoint(X: 6, Y: 1))
|
||||
XCTAssertEqual(test: "testFindLocWithMinDistance (6, 1)", withExpression: (nearest.index == 2))
|
||||
}
|
||||
|
||||
func testSolveForPart1() {
|
||||
let coor = Coordinates(withString: testData)
|
||||
let answer = coor.solveForPart1(print: false)
|
||||
XCTAssertEqual(test: "testSolveForPart1", withExpression: (answer == 17))
|
||||
}
|
||||
|
||||
func testFindSumOfAllDistances() {
|
||||
let coor = Coordinates(withString: testData)
|
||||
let sum = coor.findSumOfAllDistances(toPoint: GridPoint(X: 4, Y: 3))
|
||||
XCTAssertEqual(test: "testFindSumOfAllDistances (4, 3)", withExpression: (sum == 30))
|
||||
}
|
||||
|
||||
func testSolveForPart2() {
|
||||
let coor = Coordinates(withString: testData)
|
||||
let answer = coor.solveForPart2(print: false , withValue: 32)
|
||||
XCTAssertEqual(test: "testSolveForPart2", withExpression: (answer == 16))
|
||||
}
|
||||
|
||||
func day06Tests() {
|
||||
printGrid()
|
||||
testCoordinatesInit()
|
||||
testDistanceAtoAll()
|
||||
testFindLocWithMinDistance()
|
||||
testSolveForPart1()
|
||||
testFindSumOfAllDistances()
|
||||
testSolveForPart2()
|
||||
}
|
||||
|
||||
func day06Final() {
|
||||
let coor = Coordinates(withString: finalData)
|
||||
var answer = coor.solveForPart1(print: false)
|
||||
print("Answer to part 1 is: \(answer)")
|
||||
answer = coor.solveForPart2(print: false, withValue: 10000)
|
||||
print("Answer to part 2 is: \(answer)")
|
||||
}
|
||||
|
||||
let finalData = """
|
||||
342, 203
|
||||
79, 64
|
||||
268, 323
|
||||
239, 131
|
||||
246, 87
|
||||
161, 93
|
||||
306, 146
|
||||
43, 146
|
||||
57, 112
|
||||
241, 277
|
||||
304, 303
|
||||
143, 235
|
||||
253, 318
|
||||
97, 103
|
||||
200, 250
|
||||
67, 207
|
||||
345, 149
|
||||
133, 222
|
||||
232, 123
|
||||
156, 359
|
||||
80, 224
|
||||
51, 145
|
||||
138, 312
|
||||
339, 294
|
||||
297, 256
|
||||
163, 311
|
||||
241, 321
|
||||
126, 66
|
||||
145, 171
|
||||
359, 184
|
||||
241, 58
|
||||
108, 312
|
||||
117, 118
|
||||
101, 180
|
||||
58, 290
|
||||
324, 42
|
||||
141, 190
|
||||
270, 149
|
||||
209, 294
|
||||
296, 345
|
||||
68, 266
|
||||
233, 281
|
||||
305, 183
|
||||
245, 230
|
||||
161, 295
|
||||
335, 352
|
||||
93, 66
|
||||
227, 59
|
||||
264, 249
|
||||
116, 173
|
||||
"""
|
||||
}
|
||||
@@ -0,0 +1,305 @@
|
||||
//
|
||||
// Advent of Code 2018 "Day 7: The Sum of Its Parts"
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct Instruction: Equatable, Comparable {
|
||||
var complete = Character(" ")
|
||||
var before = Character(" ")
|
||||
|
||||
static func == (lhs: Instruction, rhs: Instruction) -> Bool {
|
||||
return (lhs.complete == rhs.complete) && (lhs.before == rhs.before)
|
||||
}
|
||||
|
||||
static func < (lhs: Instruction, rhs: Instruction) -> Bool {
|
||||
return lhs.complete < rhs.complete
|
||||
}
|
||||
}
|
||||
|
||||
struct Worker: Equatable, Comparable {
|
||||
var job = Character(" ")
|
||||
var duration = 0
|
||||
|
||||
static func == (lhs: Worker, rhs: Worker) -> Bool {
|
||||
return (lhs.job == rhs.job) && (lhs.duration == rhs.duration)
|
||||
}
|
||||
|
||||
static func < (lhs: Worker, rhs: Worker) -> Bool {
|
||||
return lhs.duration < rhs.duration
|
||||
}
|
||||
}
|
||||
|
||||
class SumParts {
|
||||
var instrList: [Instruction] = []
|
||||
var workers: [Worker] = []
|
||||
var masterClock = 0
|
||||
|
||||
// Supply filename for input ex: '/home/peterr/AOC2018/Sources/AOC2018/data/day07.txt'
|
||||
init(withFile filename: String, numWorkers: Int) {
|
||||
let instrString = Tools.readFile(fromPath: filename)
|
||||
var instrArray = instrString.components(separatedBy: "\n")
|
||||
// This gurd statement is just an excuse to use guard
|
||||
// I'm assuming the last string is an empty string, if not DON'T remove the last string
|
||||
guard let lastStr = instrArray.last, lastStr.count == 0 else { return }
|
||||
instrArray.removeLast() // empty string
|
||||
parseData(withInstructions: instrArray)
|
||||
workers = Array(repeating: Worker(), count: numWorkers)
|
||||
}
|
||||
|
||||
// Supply test data in the form of a String
|
||||
init(withString instrString: String, numWorkers: Int) {
|
||||
let instrArray = instrString.components(separatedBy: "\n")
|
||||
parseData(withInstructions: instrArray)
|
||||
workers = Array(repeating: Worker(), count: numWorkers)
|
||||
}
|
||||
|
||||
func parseData(withInstructions instr: [String]) {
|
||||
for ins in instr {
|
||||
instrList.append(Instruction(complete: ins[5], before: ins[36]))
|
||||
}
|
||||
}
|
||||
|
||||
func getNextAvailable() -> Character? {
|
||||
var retVal: Character?
|
||||
var availDict: [Character : Bool] = [:]
|
||||
for index in 0..<instrList.count {
|
||||
if !instrList.contains(where: { $0.before == instrList[index].complete} ) {
|
||||
availDict[instrList[index].complete] = true
|
||||
}
|
||||
}
|
||||
var available = Array(availDict.keys)
|
||||
available.sort()
|
||||
if workers.count == 0 {
|
||||
retVal = available.first
|
||||
} else {
|
||||
// Exclude 'available' if already scheduled to a worker
|
||||
for job in available {
|
||||
// if workers.contains(where: { $0.job == job && $0.duration == 0} ) {
|
||||
if !workers.contains(where: { $0.job == job} ) || workers.contains(where: { $0.job == job && $0.duration == 0} ) {
|
||||
retVal = job
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func completeAllInstructions() -> String {
|
||||
var retVal = ""
|
||||
var last: Character = "*"
|
||||
while let instruction = getNextAvailable() {
|
||||
retVal.append(instruction)
|
||||
if let lastInstr = instrList.first(where: { $0.complete == instruction }) {
|
||||
last = lastInstr.before
|
||||
}
|
||||
instrList.removeAll(where: { $0.complete == instruction })
|
||||
}
|
||||
retVal.append(last)
|
||||
return retVal
|
||||
}
|
||||
|
||||
func complete(instruction: Character) {
|
||||
if instrList.count == 1 && instrList[0].complete != " " {
|
||||
instrList.append(Instruction(complete: instrList[0].before, before: Character(" ")))
|
||||
}
|
||||
instrList.removeAll(where: { $0.complete == instruction })
|
||||
}
|
||||
|
||||
//-------------->> Code for Part 2 <<--------------
|
||||
|
||||
// We'll cheat here and assume the duration is 1 second + offset for One worker and 60 seconds + offset for more than one
|
||||
func duration(forInstruction instr: Character) -> Int {
|
||||
guard let val = instr.ascii else { return -1 }
|
||||
let offset = Int(val) - 64
|
||||
return (workers.count > 2) ? 60 + offset : offset
|
||||
}
|
||||
|
||||
// Go through the list of workers and find the min() time-to-finish
|
||||
func getTimeUntilWorkerFree() -> Int {
|
||||
guard workers.count > 0 else { return 0 }
|
||||
let sortedByDuration = workers.sorted(by: { $0.duration < $1.duration })
|
||||
for worker in sortedByDuration {
|
||||
if worker.duration != 0 {
|
||||
return worker.duration
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func advanceTime(by elapsedtime: Int) {
|
||||
for index in 0..<workers.count {
|
||||
if workers[index].duration > 0 {
|
||||
workers[index].duration -= elapsedtime
|
||||
}
|
||||
}
|
||||
masterClock += elapsedtime
|
||||
}
|
||||
|
||||
// subtract XX seconds from the workers time and add that to the master-clock
|
||||
// Since we advance until worker(s) done, we should complete the tasks finsished by the worker(s)
|
||||
// return true if more work to do
|
||||
func advanceClockAndCompleteInstructions() -> Bool {
|
||||
guard workers.count > 0 else { return false }
|
||||
let advTime = getTimeUntilWorkerFree()
|
||||
if advTime == 0 {
|
||||
let test = workers.contains(where: { $0.duration != 0} )
|
||||
if !test {
|
||||
return false
|
||||
}
|
||||
}
|
||||
// subtract this time from all workers
|
||||
// add this time to the Master-Clock
|
||||
advanceTime(by: advTime)
|
||||
// Complete the "finished" worker(s) instruction
|
||||
for index in 0..<workers.count {
|
||||
if workers[index].duration == 0 {
|
||||
complete(instruction: workers[index].job)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Look for available workers and assign them instructions
|
||||
func scheduleWorkers() {
|
||||
for index in 0..<workers.count {
|
||||
if workers[index].duration == 0 {
|
||||
guard let job = getNextAvailable() else { return }
|
||||
workers[index] = Worker(job: job, duration: duration(forInstruction: job))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Day07: AOCDay {
|
||||
lazy var tests: (() -> ()) = day07Tests
|
||||
lazy var final: (() -> ()) = day07Final
|
||||
|
||||
let testData = """
|
||||
Step C must be finished before step A can begin.
|
||||
Step C must be finished before step F can begin.
|
||||
Step A must be finished before step B can begin.
|
||||
Step A must be finished before step D can begin.
|
||||
Step B must be finished before step E can begin.
|
||||
Step D must be finished before step E can begin.
|
||||
Step F must be finished before step E can begin.
|
||||
"""
|
||||
|
||||
func testSumPartsInit() {
|
||||
var instr = SumParts(withString: testData, numWorkers: 0)
|
||||
XCTAssertEqual(test: "testSumPartsInit string 0", withExpression: (instr.instrList[0].before == "A"))
|
||||
XCTAssertEqual(test: "testSumPartsInit string 4", withExpression: (instr.instrList[4].complete == "B"))
|
||||
instr = SumParts(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day07.txt", numWorkers: 0)
|
||||
XCTAssertEqual(test: "testSumPartsInit file 0", withExpression: (instr.instrList[0].before == "X"))
|
||||
XCTAssertEqual(test: "testSumPartsInit file 4", withExpression: (instr.instrList[4].complete == "O"))
|
||||
}
|
||||
|
||||
func testGetNextAvailable() {
|
||||
let instr = SumParts(withString: testData, numWorkers: 0)
|
||||
if let avail = instr.getNextAvailable() {
|
||||
XCTAssertEqual(test: "testGetNextAvailable", withExpression: (avail == "C"))
|
||||
} else {
|
||||
XCTAssertEqual(test: "testGetNextAvailable", withExpression: (false))
|
||||
}
|
||||
}
|
||||
|
||||
func testCompleteInstructions() {
|
||||
let instr = SumParts(withString: testData, numWorkers: 0)
|
||||
let answer = instr.completeAllInstructions()
|
||||
XCTAssertEqual(test: "testCompleteInstructions", withExpression: (answer == "CABDFE"))
|
||||
}
|
||||
|
||||
func testDuration() {
|
||||
var instr = SumParts(withString: testData, numWorkers: 2)
|
||||
var dur = instr.duration(forInstruction: "A")
|
||||
XCTAssertEqual(test: "testDuration 1 worker A", withExpression: (dur == 1))
|
||||
dur = instr.duration(forInstruction: "K")
|
||||
XCTAssertEqual(test: "testDuration 1 worker K", withExpression: (dur == 11))
|
||||
dur = instr.duration(forInstruction: "Z")
|
||||
XCTAssertEqual(test: "testDuration 1 worker Z", withExpression: (dur == 26))
|
||||
instr = SumParts(withString: testData, numWorkers: 5)
|
||||
dur = instr.duration(forInstruction: "A")
|
||||
XCTAssertEqual(test: "testDuration 5 worker A", withExpression: (dur == 60 + 1))
|
||||
dur = instr.duration(forInstruction: "K")
|
||||
XCTAssertEqual(test: "testDuration 5 worker K", withExpression: (dur == 60 + 11))
|
||||
dur = instr.duration(forInstruction: "Z")
|
||||
XCTAssertEqual(test: "testDuration 5 worker Z", withExpression: (dur == 60 + 26))
|
||||
}
|
||||
|
||||
// Go through the list of workers and find the min() time-to-finish
|
||||
func testGetTimeUntilWorkerFree() {
|
||||
var instr = SumParts(withString: testData, numWorkers: 2)
|
||||
var time = instr.getTimeUntilWorkerFree()
|
||||
XCTAssertEqual(test: "testGetTimeUntilWorkerFree 1 worker", withExpression: (time == 0))
|
||||
instr = SumParts(withString: testData, numWorkers: 5)
|
||||
time = instr.getTimeUntilWorkerFree()
|
||||
XCTAssertEqual(test: "testGetTimeUntilWorkerFree 5 workers", withExpression: (time == 0))
|
||||
}
|
||||
|
||||
func testAdvanceTime() {
|
||||
let instr = SumParts(withString: testData, numWorkers: 2)
|
||||
let oldClock = instr.masterClock
|
||||
let oldWorkers = instr.workers
|
||||
instr.advanceTime(by: 0)
|
||||
XCTAssertEqual(test: "testAdvanceTime by 0 seconds clock", withExpression: (oldClock == instr.masterClock))
|
||||
XCTAssertEqual(test: "testAdvanceTime by 0 seconds workers", withExpression: (oldWorkers == instr.workers))
|
||||
instr.advanceTime(by: 10)
|
||||
XCTAssertEqual(test: "testAdvanceTime by 10 seconds clock", withExpression: (instr.masterClock == 10))
|
||||
}
|
||||
|
||||
// subtract XX seconds from the workers time and add that to the master-clock
|
||||
// Since we advance until worker(s) done, we should complete the tasks finsished by the worker(s)
|
||||
func testAdvanceClockAndCompleteInstructions() {
|
||||
let instr = SumParts(withString: testData, numWorkers: 2)
|
||||
let oldWorkers = instr.workers
|
||||
var done = instr.advanceClockAndCompleteInstructions()
|
||||
XCTAssertEqual(test: "testAdvanceClockAndCompleteInstructions done=false before first schedule", withExpression: (!done))
|
||||
XCTAssertEqual(test: "testAdvanceClockAndCompleteInstructions workers unchanged", withExpression: (oldWorkers == instr.workers))
|
||||
XCTAssertEqual(test: "testAdvanceClockAndCompleteInstructions masterClock unchanged", withExpression: (instr.masterClock == 0))
|
||||
instr.scheduleWorkers()
|
||||
done = instr.advanceClockAndCompleteInstructions()
|
||||
XCTAssertEqual(test: "testAdvanceClockAndCompleteInstructions done=true after first schedule", withExpression: (done))
|
||||
}
|
||||
|
||||
// Look for available workers and assign them instructions
|
||||
func testScheduleWorkers() {
|
||||
let instr = SumParts(withString: testData, numWorkers: 2)
|
||||
let oldWorkers = instr.workers
|
||||
instr.scheduleWorkers()
|
||||
XCTAssertEqual(test: "testScheduleWorkers workers changed", withExpression: (oldWorkers != instr.workers))
|
||||
}
|
||||
|
||||
func testAnswerPart2() {
|
||||
let instr = SumParts(withString: testData, numWorkers: 2)
|
||||
instr.scheduleWorkers()
|
||||
while instr.advanceClockAndCompleteInstructions() {
|
||||
instr.scheduleWorkers()
|
||||
}
|
||||
XCTAssertEqual(test: "testAnswerPart2", withExpression: (instr.masterClock == 15))
|
||||
}
|
||||
|
||||
func day07Tests() {
|
||||
testSumPartsInit()
|
||||
testGetNextAvailable()
|
||||
testCompleteInstructions()
|
||||
testDuration()
|
||||
testGetTimeUntilWorkerFree()
|
||||
testAdvanceTime()
|
||||
testAdvanceClockAndCompleteInstructions()
|
||||
testScheduleWorkers()
|
||||
testAnswerPart2()
|
||||
}
|
||||
|
||||
func day07Final() {
|
||||
var instr = SumParts(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day07.txt", numWorkers: 0)
|
||||
let answerPart1 = instr.completeAllInstructions()
|
||||
instr = SumParts(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day07.txt", numWorkers: 5)
|
||||
instr.scheduleWorkers()
|
||||
while instr.advanceClockAndCompleteInstructions() {
|
||||
instr.scheduleWorkers()
|
||||
}
|
||||
let answerPart2 = instr.masterClock
|
||||
print("Answer to part 1 is: \(answerPart1)")
|
||||
print("Answer to part 2 is: \(answerPart2)")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
//
|
||||
// Advent of Code 2018 "Day 8: Memory Maneuver"
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct Header {
|
||||
var nChildren = 0
|
||||
var nMeta = 0
|
||||
}
|
||||
|
||||
struct Node {
|
||||
var header = Header(nChildren: 0, nMeta: 0)
|
||||
var children: [Node] = []
|
||||
var meta: [Int] = []
|
||||
var length = 2 // Smallest node is only a header with no children or meta data
|
||||
}
|
||||
|
||||
class Maneuver {
|
||||
var treeData: [Int] = []
|
||||
var sumMeta = 0
|
||||
|
||||
// Supply filename for input ex: '/home/peterr/AOC2018/Sources/AOC2018/data/day08.txt'
|
||||
init(withFile filename: String) {
|
||||
let tree = Tools.readFile(fromPath: filename)
|
||||
let chars = tree.components(separatedBy: " ")
|
||||
for char in chars {
|
||||
treeData.append(Int(char) ?? -1)
|
||||
}
|
||||
}
|
||||
|
||||
// Supply test data in the form of a String
|
||||
init(withString tree: String) {
|
||||
let chars = tree.components(separatedBy: " ")
|
||||
for char in chars {
|
||||
treeData.append(Int(char) ?? -1)
|
||||
}
|
||||
}
|
||||
|
||||
// get length of node and sum th meta data for Part 1 as a by-product
|
||||
func getLength(ofChild childData: ArraySlice<Int>) -> Int {
|
||||
let nChildren = childData[childData.startIndex]
|
||||
let nMetaIndex = childData.index(after: childData.startIndex)
|
||||
let nMeta = childData[nMetaIndex]
|
||||
var length = 2
|
||||
|
||||
if nChildren == 0 {
|
||||
let start = childData.startIndex + 2
|
||||
let metaData = Array(childData[start..<start+nMeta])
|
||||
for meta in metaData {
|
||||
sumMeta += meta
|
||||
}
|
||||
return length + nMeta
|
||||
} else {
|
||||
var childIndex = nMetaIndex + 1
|
||||
for _ in 0..<nChildren {
|
||||
let childLength = getLength(ofChild: childData[childIndex...])
|
||||
childIndex += childLength
|
||||
length += childLength
|
||||
}
|
||||
let metaData = Array(childData[childIndex..<childIndex+nMeta])
|
||||
for meta in metaData {
|
||||
sumMeta += meta
|
||||
}
|
||||
length += nMeta
|
||||
}
|
||||
return length
|
||||
}
|
||||
|
||||
func getNode(withChild childData: ArraySlice<Int>) -> Node {
|
||||
let nChildren = childData[childData.startIndex]
|
||||
let nMetaIndex = childData.index(after: childData.startIndex)
|
||||
let nMeta = childData[nMetaIndex]
|
||||
var metaData: [Int] = []
|
||||
let children: [Node] = []
|
||||
var retVal = Node(header: Header(nChildren: nChildren, nMeta: nMeta), children: children, meta: metaData, length: 2)
|
||||
|
||||
if nChildren == 0 {
|
||||
let start = childData.startIndex + 2
|
||||
metaData = Array(childData[start..<start+nMeta])
|
||||
} else {
|
||||
var childIndex = nMetaIndex + 1
|
||||
for _ in 0..<nChildren {
|
||||
let childLength = getLength(ofChild: childData[childIndex...])
|
||||
retVal.children.append(getNode(withChild: childData[childIndex...]))
|
||||
childIndex += childLength
|
||||
retVal.length += childLength
|
||||
}
|
||||
metaData = Array(childData[childIndex..<childIndex+nMeta])
|
||||
}
|
||||
retVal.meta = metaData
|
||||
retVal.length += nMeta
|
||||
return retVal
|
||||
}
|
||||
|
||||
func getValue(forNode node: Node) -> Int {
|
||||
var retVal = 0
|
||||
if (node.header.nChildren == 0) {
|
||||
for meta in node.meta {
|
||||
retVal += meta
|
||||
}
|
||||
} else {
|
||||
for meta in node.meta {
|
||||
let childIndex = meta - 1
|
||||
if (0..<node.children.count).contains(childIndex) {
|
||||
let childNode = node.children[childIndex]
|
||||
retVal += getValue(forNode: childNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
}
|
||||
|
||||
class Day08: AOCDay {
|
||||
lazy var tests: (() -> ()) = day08Tests
|
||||
lazy var final: (() -> ()) = day08Final
|
||||
|
||||
let testData = "2 3 0 3 10 11 12 1 1 0 1 99 2 1 1 2"
|
||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
|
||||
// A----------------16----------------
|
||||
// B-----5----- C-----6-----
|
||||
// D-3---
|
||||
|
||||
func testManeuverInit() {
|
||||
var maneu = Maneuver(withString: testData)
|
||||
XCTAssertEqual(test: "testManeuverInit string", withExpression: (maneu.treeData[3] == 3))
|
||||
maneu = Maneuver(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day08.txt")
|
||||
XCTAssertEqual(test: "testManeuverInit file [3]", withExpression: (maneu.treeData[3] == 2))
|
||||
XCTAssertEqual(test: "testManeuverInit file last", withExpression: (maneu.treeData.last! == 1))
|
||||
}
|
||||
|
||||
func testGetLength() {
|
||||
let maneu = Maneuver(withString: testData)
|
||||
let totalLen = maneu.getLength(ofChild: maneu.treeData[0...])
|
||||
XCTAssertEqual(test: "testGetLength", withExpression: (totalLen == 16))
|
||||
XCTAssertEqual(test: "testGetLength sum Meta", withExpression: (maneu.sumMeta == 138))
|
||||
}
|
||||
|
||||
func testGetNode() {
|
||||
let maneu = Maneuver(withString: testData)
|
||||
let node = maneu.getNode(withChild: maneu.treeData[0...])
|
||||
XCTAssertEqual(test: "testGetNode", withExpression: (node.length == 16))
|
||||
}
|
||||
|
||||
func testGetValue() {
|
||||
let maneu = Maneuver(withString: testData)
|
||||
let node = maneu.getNode(withChild: maneu.treeData[0...])
|
||||
let value = maneu.getValue(forNode: node)
|
||||
XCTAssertEqual(test: "testGetValue", withExpression: (value == 66))
|
||||
}
|
||||
|
||||
func day08Tests() {
|
||||
testManeuverInit()
|
||||
testGetLength()
|
||||
testGetNode()
|
||||
testGetValue()
|
||||
}
|
||||
|
||||
func day08Final() {
|
||||
var maneu = Maneuver(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day08.txt")
|
||||
_ = maneu.getLength(ofChild: maneu.treeData[0...])
|
||||
print("Answer to part 1 is: \(maneu.sumMeta)")
|
||||
maneu = Maneuver(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day08.txt")
|
||||
let node = maneu.getNode(withChild: maneu.treeData[0...])
|
||||
let value = maneu.getValue(forNode: node)
|
||||
print("Answer to part 2 is: \(value)")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
//
|
||||
// Advent of Code 2018 "Day 9: Marble Mania"
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct List {
|
||||
var val = 0
|
||||
var ptrNext = -1
|
||||
var ptrPrev = -1
|
||||
}
|
||||
|
||||
class Marble {
|
||||
var player: [Int] = []
|
||||
var lastMarble = 0
|
||||
var circle: [List] = []
|
||||
var circleCount = 1
|
||||
var currentMarble = 0
|
||||
var currentPlayer = 0
|
||||
var PC = 0
|
||||
|
||||
init(numPlayers: Int, lastMarble last: Int) {
|
||||
circle = Array(repeating: List(), count: last+1)
|
||||
circleCount = 1
|
||||
currentMarble = 0
|
||||
currentPlayer = 0
|
||||
PC = 0
|
||||
circle[0].ptrNext = 0
|
||||
circle[0].ptrPrev = 0
|
||||
|
||||
player = Array(repeating: 0, count: numPlayers)
|
||||
for num in 0...last { circle[num].val = num }
|
||||
lastMarble = last
|
||||
}
|
||||
|
||||
func insert() {
|
||||
circle[currentMarble].ptrNext = circle[PC].val
|
||||
circle[currentMarble].ptrPrev = circle[PC].ptrPrev
|
||||
circle[circle[PC].ptrPrev].ptrNext = circle[currentMarble].val
|
||||
circle[PC].ptrPrev = circle[currentMarble].val
|
||||
PC = currentMarble
|
||||
circleCount += 1
|
||||
}
|
||||
|
||||
func remove() {
|
||||
circle[circle[PC].ptrPrev].ptrNext = circle[PC].ptrNext
|
||||
circle[circle[PC].ptrNext].ptrPrev = circle[PC].ptrPrev
|
||||
PC = circle[circle[PC].ptrPrev].ptrNext
|
||||
circleCount -= 1
|
||||
}
|
||||
|
||||
func incrPC() {
|
||||
PC = circle[PC].ptrNext
|
||||
}
|
||||
|
||||
func incrPC(by n: Int) {
|
||||
for _ in 0..<n { incrPC() }
|
||||
}
|
||||
|
||||
func decrPC() {
|
||||
PC = circle[PC].ptrPrev
|
||||
}
|
||||
|
||||
func decrPC(by n: Int) {
|
||||
for _ in 0..<n { decrPC() }
|
||||
}
|
||||
|
||||
func incrPlayer() {
|
||||
currentPlayer += 1
|
||||
if currentPlayer == player.count { currentPlayer = 0 }
|
||||
}
|
||||
|
||||
func placeNextMarble() {
|
||||
currentMarble += 1
|
||||
if currentMarble % 23 == 0 {
|
||||
player[currentPlayer] += currentMarble
|
||||
decrPC(by: 7)
|
||||
player[currentPlayer] += circle[PC].val
|
||||
remove()
|
||||
} else {
|
||||
incrPC(by: 2)
|
||||
insert()
|
||||
}
|
||||
incrPlayer()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Day09: AOCDay {
|
||||
lazy var tests: (() -> ()) = day09Tests
|
||||
lazy var final: (() -> ()) = day09Final
|
||||
|
||||
let testData: [(Int, Int, Int)] = [
|
||||
(9, 25, 32),
|
||||
(13, 7999, 146373),
|
||||
(17, 1104, 2764),
|
||||
(21, 6111, 54718),
|
||||
(30, 5807, 37305)
|
||||
]
|
||||
|
||||
let finalData = (477, 70851)
|
||||
|
||||
func printCircle(circle: [List], withCount circleCount: Int) -> String {
|
||||
var retVal = ""
|
||||
var marble = circle[0]
|
||||
for _ in 0..<circleCount {
|
||||
retVal += "\(marble.val), "
|
||||
marble = circle[marble.ptrNext]
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func testMarbleInit() {
|
||||
let marb = Marble(numPlayers: 9, lastMarble: 15)
|
||||
let result = printCircle(circle: marb.circle, withCount: marb.circleCount)
|
||||
XCTAssertEqual(test: "testMarbleInit num", withExpression: (marb.player.count == 9))
|
||||
XCTAssertEqual(test: "testMarbleInit last", withExpression: (marb.lastMarble == 15))
|
||||
XCTAssertEqual(test: "testMarbleInit result", withExpression: (result == "0, "))
|
||||
}
|
||||
|
||||
func testInsert() {
|
||||
let marb = Marble(numPlayers: 9, lastMarble: 15)
|
||||
for _ in 0...3 {
|
||||
marb.currentMarble += 1
|
||||
marb.insert()
|
||||
marb.incrPC(by:2)
|
||||
}
|
||||
let result = printCircle(circle: marb.circle, withCount: marb.circleCount)
|
||||
XCTAssertEqual(test: "testInsert result", withExpression: (result == "0, 4, 2, 1, 3, "))
|
||||
}
|
||||
|
||||
func testRemove() {
|
||||
let marb = Marble(numPlayers: 9, lastMarble: 15)
|
||||
for _ in 0...3 {
|
||||
marb.currentMarble += 1
|
||||
marb.insert()
|
||||
marb.incrPC(by:2)
|
||||
}
|
||||
marb.decrPC(by: 2)
|
||||
marb.remove()
|
||||
let result = printCircle(circle: marb.circle, withCount: marb.circleCount)
|
||||
XCTAssertEqual(test: "testRemove result", withExpression: (result == "0, 2, 1, 3, "))
|
||||
}
|
||||
|
||||
func testPlaceNextMarble() {
|
||||
var result = ""
|
||||
for data in testData {
|
||||
let marb = Marble(numPlayers: data.0, lastMarble: data.1)
|
||||
for _ in 0..<marb.lastMarble {
|
||||
marb.placeNextMarble()
|
||||
if data == (9, 25, 32) {
|
||||
result = printCircle(circle: marb.circle, withCount: marb.circleCount)
|
||||
}
|
||||
}
|
||||
let max = marb.player.max() ?? 0
|
||||
if data == (9, 25, 32) {
|
||||
XCTAssertEqual(test: "testPlaceMarble result", withExpression: (result == "0, 16, 8, 17, 4, 18, 19, 2, 24, 20, 25, 10, 21, 5, 22, 11, 1, 12, 6, 13, 3, 14, 7, 15, "))
|
||||
}
|
||||
XCTAssertEqual(test: "testPlaceMarble \(data)", withExpression: (max == data.2))
|
||||
}
|
||||
}
|
||||
|
||||
func day09Tests() {
|
||||
testMarbleInit()
|
||||
testInsert()
|
||||
testRemove()
|
||||
testPlaceNextMarble()
|
||||
}
|
||||
|
||||
func day09Final() {
|
||||
var marb = Marble(numPlayers: 477, lastMarble: 70851)
|
||||
for _ in 0..<marb.lastMarble {
|
||||
marb.placeNextMarble()
|
||||
}
|
||||
var max = marb.player.max() ?? 0
|
||||
print("Answer to part 1 is: \(max)")
|
||||
marb = Marble(numPlayers: 477, lastMarble: 7085100)
|
||||
for i in 0..<marb.lastMarble {
|
||||
marb.placeNextMarble()
|
||||
if i % 1000000 == 0 { print("\(i)")}
|
||||
}
|
||||
max = marb.player.max() ?? 0
|
||||
print("Answer to part 2 is: \(max)")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
//
|
||||
// Advent of Code 2018 "Day 10: The Stars Align"
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class Align {
|
||||
var pt: [(Int, Int)] = []
|
||||
var vel: [(Int, Int)] = []
|
||||
|
||||
// Supply filename for input ex: '/home/peterr/AOC2018/Sources/AOC2018/data/day10.txt'
|
||||
init(withFile filename: String) {
|
||||
let starFile = Tools.readFile(fromPath: filename)
|
||||
var starStrings = starFile.components(separatedBy: "\n")
|
||||
// This gurd statement is just an excuse to use guard
|
||||
// I'm assuming the last string is an empty string, if not DON'T remove the last string
|
||||
guard let lastStr = starStrings.last, lastStr.count == 0 else { return }
|
||||
starStrings.removeLast() // empty string
|
||||
parseData(withStars: starStrings)
|
||||
}
|
||||
|
||||
// Supply test data in the form of a String
|
||||
init(withString starFile: String) {
|
||||
let starStrings = starFile.components(separatedBy: "\n")
|
||||
parseData(withStars: starStrings)
|
||||
}
|
||||
|
||||
func parseData(withStars starArray: [String]) {
|
||||
for star in starArray {
|
||||
var line = star
|
||||
line = line.replacingOccurrences(of: "position=<", with: "")
|
||||
line = line.replacingOccurrences(of: "> velocity=<", with: ", ")
|
||||
line = line.replacingOccurrences(of: ">", with: "")
|
||||
line = line.replacingOccurrences(of: " ", with: "")
|
||||
let data = line.components(separatedBy: ",")
|
||||
guard data.count == 4 else { print("Error"); return }
|
||||
pt.append((Int(data[0]) ?? 0, Int(data[1]) ?? 0))
|
||||
vel.append((Int(data[2]) ?? 0, Int(data[3]) ?? 0))
|
||||
}
|
||||
}
|
||||
|
||||
func advanceTime(by n: Int) -> [(Int, Int)] {
|
||||
var newpt: [(Int, Int)] = []
|
||||
for index in 0..<pt.count {
|
||||
let x = pt[index].0 + vel[index].0 * n
|
||||
let y = pt[index].1 + vel[index].1 * n
|
||||
newpt.append((x, y))
|
||||
}
|
||||
return newpt
|
||||
}
|
||||
|
||||
func potentialMessage(withGrid grid: [(Int, Int)]) -> Int {
|
||||
var xs: [Int] = []
|
||||
var ys: [Int] = []
|
||||
for point in grid {
|
||||
xs.append(point.0)
|
||||
ys.append(point.1)
|
||||
}
|
||||
var lineCount = 0
|
||||
for point in grid {
|
||||
lineCount += xs.filter{$0 == point.0}.count
|
||||
lineCount *= ys.filter{$0 == point.1}.count
|
||||
break
|
||||
}
|
||||
if lineCount > 123 {
|
||||
printGrid(points: grid, minX: xs.min()!, maxX: xs.max()!, minY: ys.min()!, maxY: ys.max()!)
|
||||
}
|
||||
return lineCount
|
||||
}
|
||||
|
||||
func printGrid(points: [(Int, Int)], minX: Int, maxX: Int, minY: Int, maxY: Int) {
|
||||
for j in minY-1...maxY+1 {
|
||||
for i in minX-1...maxX+1 {
|
||||
if points.contains(where: { $0.0 == i && $0.1 == j }) {
|
||||
print("XX", terminator: "")
|
||||
} else {
|
||||
print("..", terminator: "")
|
||||
}
|
||||
}
|
||||
print("")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
class Day10: AOCDay {
|
||||
lazy var tests: (() -> ()) = day10Tests
|
||||
lazy var final: (() -> ()) = day10Final
|
||||
|
||||
let testData = """
|
||||
position=< 9, 1> velocity=< 0, 2>
|
||||
position=< 7, 0> velocity=<-1, 0>
|
||||
position=< 3, -2> velocity=<-1, 1>
|
||||
position=< 6, 10> velocity=<-2, -1>
|
||||
position=< 2, -4> velocity=< 2, 2>
|
||||
position=<-6, 10> velocity=< 2, -2>
|
||||
position=< 1, 8> velocity=< 1, -1>
|
||||
position=< 1, 7> velocity=< 1, 0>
|
||||
position=<-3, 11> velocity=< 1, -2>
|
||||
position=< 7, 6> velocity=<-1, -1>
|
||||
position=<-2, 3> velocity=< 1, 0>
|
||||
position=<-4, 3> velocity=< 2, 0>
|
||||
position=<10, -3> velocity=<-1, 1>
|
||||
position=< 5, 11> velocity=< 1, -2>
|
||||
position=< 4, 7> velocity=< 0, -1>
|
||||
position=< 8, -2> velocity=< 0, 1>
|
||||
position=<15, 0> velocity=<-2, 0>
|
||||
position=< 1, 6> velocity=< 1, 0>
|
||||
position=< 8, 9> velocity=< 0, -1>
|
||||
position=< 3, 3> velocity=<-1, 1>
|
||||
position=< 0, 5> velocity=< 0, -1>
|
||||
position=<-2, 2> velocity=< 2, 0>
|
||||
position=< 5, -2> velocity=< 1, 2>
|
||||
position=< 1, 4> velocity=< 2, 1>
|
||||
position=<-2, 7> velocity=< 2, -2>
|
||||
position=< 3, 6> velocity=<-1, -1>
|
||||
position=< 5, 0> velocity=< 1, 0>
|
||||
position=<-6, 0> velocity=< 2, 0>
|
||||
position=< 5, 9> velocity=< 1, -2>
|
||||
position=<14, 7> velocity=<-2, 0>
|
||||
position=<-3, 6> velocity=< 2, -1>
|
||||
"""
|
||||
|
||||
func testAlignInit() {
|
||||
let _ = Align(withString: testData)
|
||||
let _ = Align(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day10.txt")
|
||||
}
|
||||
|
||||
func testAdvanceTime() {
|
||||
let algn = Align(withString: testData)
|
||||
let newGrid = algn.advanceTime(by: 3)
|
||||
algn.printGrid(points: newGrid, minX: 0, maxX: 9, minY: 0, maxY: 7)
|
||||
}
|
||||
|
||||
func testPotentialMessage() {
|
||||
let algn = Align(withString: testData)
|
||||
var bestTime = 0
|
||||
for time in 0...10 {
|
||||
let newGrid = algn.advanceTime(by: time)
|
||||
let mFactor = algn.potentialMessage(withGrid: newGrid)
|
||||
if mFactor >= 10 {
|
||||
bestTime = time
|
||||
break
|
||||
}
|
||||
}
|
||||
XCTAssertEqual(test: "testPotentialMessage", withExpression: (bestTime == 3))
|
||||
}
|
||||
|
||||
|
||||
func day10Tests() {
|
||||
testAlignInit()
|
||||
testAdvanceTime()
|
||||
testPotentialMessage()
|
||||
}
|
||||
|
||||
func day10Final() {
|
||||
// let retVal = "None"
|
||||
// print("Answer to part 1 is: \(retVal)")
|
||||
var bestTime = 0
|
||||
let algn = Align(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day10.txt")
|
||||
for time in 0...100000 {
|
||||
let newGrid = algn.advanceTime(by: time)
|
||||
let mFactor = algn.potentialMessage(withGrid: newGrid)
|
||||
if mFactor > 123 {
|
||||
// print("mFactor [\(time)] = \(mFactor), time = \(time)")
|
||||
bestTime = time
|
||||
break
|
||||
}
|
||||
}
|
||||
print("Answer to part 2 is: \(bestTime)")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
//
|
||||
// Advent of Code 2018 "Day 11: Chronal Charge"
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class Charge {
|
||||
var grid: [Int] = []
|
||||
|
||||
init(withSerialNumber num: Int) {
|
||||
grid = Array(repeating: 0, count: 300 * 300)
|
||||
for j in 0..<300 {
|
||||
for i in 0..<300 {
|
||||
// grid[j * 300 + i] =
|
||||
let ID = i + 11
|
||||
let power = (ID * (j + 1) + num) * ID
|
||||
// print("power[\(i+1),\(j+1)] : \(power), \(power/1000)")
|
||||
if power < 100 {
|
||||
print("_____________________> WOW <__________________")
|
||||
}
|
||||
grid[j*300+i] = (power - (power/1000) * 1000 - (power % 100))/100 - 5
|
||||
// print("\(power % 100), mynum = \(mynum)")
|
||||
// if (i == 2) { break }
|
||||
}
|
||||
// if j == 4 { break }
|
||||
}
|
||||
}
|
||||
|
||||
func getVal(for pt: (Int, Int)) -> Int {
|
||||
return grid[(pt.1 - 1) * 300 + (pt.0 - 1)]
|
||||
}
|
||||
|
||||
func sum(for pt: (Int, Int, Int)) -> Int {
|
||||
let x = pt.0 - 1
|
||||
let y = pt.1 - 1
|
||||
let size = pt.2 - 1
|
||||
var sum = 0
|
||||
for j in y...y+size {
|
||||
for i in x...x+size {
|
||||
sum += grid[j*300+i]
|
||||
// print("\(grid[j*300+i])", terminator: " ")
|
||||
}
|
||||
// print("")
|
||||
}
|
||||
// for j in pt.1-2...pt.1+2 {
|
||||
// for i in pt.0-2...pt.0+2 {
|
||||
// // print("\(grid[j*300+i])", terminator: " ")
|
||||
// print(NSString(format:"%4d", grid[j*300+i]), terminator: "")
|
||||
// }
|
||||
// print("")
|
||||
// }
|
||||
// print("sum:\(sum)")
|
||||
return sum
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Day11: AOCDay {
|
||||
lazy var tests: (() -> ()) = day11Tests
|
||||
lazy var final: (() -> ()) = day11Final
|
||||
|
||||
func testInitCharge() {
|
||||
let _ = Charge(withSerialNumber: 5093)
|
||||
// let cha = Charge(withSerialNumber: 8)
|
||||
}
|
||||
|
||||
func testPoint() {
|
||||
var cha = Charge(withSerialNumber: 57)
|
||||
var val = cha.getVal(for: (122, 79))
|
||||
XCTAssertEqual(test: "testPoint (122,79)", withExpression: (val == -5))
|
||||
cha = Charge(withSerialNumber: 39)
|
||||
val = cha.getVal(for: (217, 196))
|
||||
XCTAssertEqual(test: "testPoint (217,196)", withExpression: (val == 0))
|
||||
cha = Charge(withSerialNumber: 71)
|
||||
val = cha.getVal(for: (101, 153))
|
||||
XCTAssertEqual(test: "testPoint (101,153)", withExpression: (val == 4))
|
||||
}
|
||||
|
||||
func testSum() {
|
||||
var cha = Charge(withSerialNumber: 18)
|
||||
var sum = cha.sum(for: (33, 45, 3))
|
||||
XCTAssertEqual(test: "testSum (33,45)", withExpression: (sum == 29))
|
||||
cha = Charge(withSerialNumber: 42)
|
||||
sum = cha.sum(for: (21, 61, 3))
|
||||
XCTAssertEqual(test: "testSum (21,61)", withExpression: (sum == 30))
|
||||
}
|
||||
|
||||
func day11Tests() {
|
||||
testInitCharge()
|
||||
testPoint()
|
||||
testSum()
|
||||
}
|
||||
|
||||
func day11Final() {
|
||||
// let retVal = "None"
|
||||
let cha = Charge(withSerialNumber: 5093)
|
||||
var maxSum = 0
|
||||
var maxCoord = (0,0)
|
||||
for y in 1...298 {
|
||||
for x in 1...298 {
|
||||
let sum = cha.sum(for: (x, y, 3))
|
||||
if sum > maxSum {
|
||||
maxSum = sum
|
||||
maxCoord = (x, y)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
print("Answer to part 1 is: \(maxCoord)")
|
||||
|
||||
// var maxSize = 0
|
||||
// var outerMaxSum = 0
|
||||
// var outerMaxCoord = (0,0)
|
||||
// for size in 1...300 {
|
||||
// maxSum = 0
|
||||
// maxCoord = (0,0)
|
||||
// for y in 1...300 - size + 1 {
|
||||
// for x in 1...300 - size + 1 {
|
||||
// let sum = cha.sum(for: (x, y, size))
|
||||
// if sum > maxSum {
|
||||
// maxSum = sum
|
||||
// maxCoord = (x, y)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if maxSum > outerMaxSum {
|
||||
// outerMaxSum = maxSum
|
||||
// outerMaxCoord = maxCoord
|
||||
// maxSize = size
|
||||
// }
|
||||
// print("\(outerMaxCoord), \(maxSize)")
|
||||
// }
|
||||
// print("Answer to part 2 is: \(outerMaxCoord), \(maxSize)")
|
||||
print("Answer to part 2 is: look for repeating cycle - takes too long to run as part of CI")
|
||||
}
|
||||
}
|
||||
|
||||
// RackID = X + 10
|
||||
// Power = RackID * Y
|
||||
// Power += SerialNumber
|
||||
// Power *= Power * RackID
|
||||
// Power = "hundreds digit"
|
||||
// Power -= 5
|
||||
@@ -0,0 +1,175 @@
|
||||
//
|
||||
// Advent of Code 2018 "Day 12: Subterranean Sustainability"
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class Sustainability {
|
||||
var condition = ""
|
||||
var pattern: [String: String] = [:]
|
||||
var keyLength = 0
|
||||
var paddingLength = 0
|
||||
|
||||
// Supply test data in the form of a String
|
||||
init(withString noteList: String, andInitialCondition initial: String, padding pad: Int) {
|
||||
paddingLength = pad
|
||||
let padding = String(Array(repeating: ".", count: paddingLength))
|
||||
condition = padding + initial + padding
|
||||
let noteStrings = noteList.components(separatedBy: "\n")
|
||||
parseData(withNotes: noteStrings)
|
||||
}
|
||||
|
||||
func parseData(withNotes noteArray: [String]) {
|
||||
for oneNote in noteArray {
|
||||
var line = oneNote
|
||||
line = line.replacingOccurrences(of: " => ", with: " ")
|
||||
let data = line.components(separatedBy: " ")
|
||||
guard data.count == 2 else { print("Error"); return }
|
||||
pattern[data[0]] = data[1]
|
||||
keyLength = data[0].count
|
||||
}
|
||||
}
|
||||
|
||||
func nextGeneration(with previous: String) -> String {
|
||||
var nextGen = String(Array(repeating: ".", count: keyLength/2))
|
||||
for i in 0..<previous.count-keyLength {
|
||||
let start = previous.index(previous.startIndex, offsetBy: i)
|
||||
let end = previous.index(previous.startIndex, offsetBy: i + keyLength)
|
||||
let range = start..<end
|
||||
let substr = String(previous[range])
|
||||
if pattern[substr] == nil {
|
||||
nextGen += "."
|
||||
} else {
|
||||
nextGen = nextGen + pattern[substr]!
|
||||
}
|
||||
}
|
||||
nextGen += String(Array(repeating: ".", count: keyLength/2+1))
|
||||
return nextGen
|
||||
}
|
||||
|
||||
func getValue(of plants: String) -> Int {
|
||||
var value = 0
|
||||
let start = -paddingLength
|
||||
for i in 0..<plants.count {
|
||||
let pot = start + i
|
||||
value += plants[i] == "#" ? pot : 0
|
||||
}
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
class Day12: AOCDay {
|
||||
lazy var tests: (() -> ()) = day12Tests
|
||||
lazy var final: (() -> ()) = day12Final
|
||||
|
||||
func testSustainabilityInit() {
|
||||
let _ = Sustainability(withString: testNotes, andInitialCondition: testInitialState, padding: 15)
|
||||
}
|
||||
|
||||
func testNextGeneration() {
|
||||
let sus = Sustainability(withString: testNotes, andInitialCondition: testInitialState, padding: 15)
|
||||
var gen = sus.condition
|
||||
print(" 0", terminator: ": ")
|
||||
print("\(gen)")
|
||||
for i in 1...20 {
|
||||
print(NSString(format:"%2d", i), terminator: ": ")
|
||||
gen = sus.nextGeneration(with: gen)
|
||||
print("\(gen)")
|
||||
}
|
||||
}
|
||||
|
||||
func testGetVaue() {
|
||||
let sus = Sustainability(withString: testNotes, andInitialCondition: testInitialState, padding: 15)
|
||||
var gen = sus.condition
|
||||
for _ in 1...20 {
|
||||
gen = sus.nextGeneration(with: gen)
|
||||
}
|
||||
let value = sus.getValue(of: gen)
|
||||
XCTAssertEqual(test: "testGetVaue", withExpression: (value == 325))
|
||||
}
|
||||
|
||||
func day12Tests() {
|
||||
testSustainabilityInit()
|
||||
testNextGeneration()
|
||||
testGetVaue()
|
||||
}
|
||||
|
||||
func day12Final() {
|
||||
let sus = Sustainability(withString: finalNotes, andInitialCondition: finalInitialState, padding: 200)
|
||||
var gen = sus.condition
|
||||
for _ in 1...20 {
|
||||
gen = sus.nextGeneration(with: gen)
|
||||
}
|
||||
let value = sus.getValue(of: gen)
|
||||
print("Answer to part 1 is: \(value)")
|
||||
|
||||
|
||||
let limitCount = 150
|
||||
var inc = 0 //40
|
||||
gen = sus.condition
|
||||
for _ in 1...limitCount {
|
||||
let preValue = sus.getValue(of: gen)
|
||||
gen = sus.nextGeneration(with: gen)
|
||||
let postValue = sus.getValue(of: gen)
|
||||
inc = postValue - preValue
|
||||
}
|
||||
let valLimit = sus.getValue(of: gen)
|
||||
let generations = 50000000000 - limitCount
|
||||
let answer = generations * inc + valLimit
|
||||
print("Answer to part 2 is: \(answer)")
|
||||
}
|
||||
}
|
||||
|
||||
var testInitialState = "#..#.#..##......###...###"
|
||||
var testNotes = """
|
||||
...## => #
|
||||
..#.. => #
|
||||
.#... => #
|
||||
.#.#. => #
|
||||
.#.## => #
|
||||
.##.. => #
|
||||
.#### => #
|
||||
#.#.# => #
|
||||
#.### => #
|
||||
##.#. => #
|
||||
##.## => #
|
||||
###.. => #
|
||||
###.# => #
|
||||
####. => #
|
||||
"""
|
||||
|
||||
var finalInitialState = "##.......#.######.##..#...#.#.#..#...#..####..#.##...#....#...##..#..#.##.##.###.##.#.......###....#"
|
||||
var finalNotes = """
|
||||
.#### => .
|
||||
....# => .
|
||||
###.. => .
|
||||
..#.# => .
|
||||
##### => #
|
||||
####. => .
|
||||
#.##. => #
|
||||
#.#.# => .
|
||||
##.#. => #
|
||||
.###. => .
|
||||
#..#. => #
|
||||
###.# => .
|
||||
#.### => .
|
||||
##... => #
|
||||
.#.## => .
|
||||
..#.. => .
|
||||
#...# => #
|
||||
..... => .
|
||||
.##.. => .
|
||||
...#. => .
|
||||
#.#.. => .
|
||||
.#..# => #
|
||||
.#.#. => .
|
||||
.#... => #
|
||||
..##. => .
|
||||
#..## => .
|
||||
##.## => #
|
||||
...## => #
|
||||
..### => #
|
||||
#.... => .
|
||||
.##.# => #
|
||||
##..# => #
|
||||
"""
|
||||
@@ -0,0 +1,380 @@
|
||||
//
|
||||
// Advent of Code 2018 "Day 13: Mine Cart Madness"
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum Sequence: Int {
|
||||
case left
|
||||
case straight
|
||||
case right
|
||||
}
|
||||
|
||||
enum Direction: Int {
|
||||
case up
|
||||
case right
|
||||
case down
|
||||
case left
|
||||
}
|
||||
|
||||
struct Cart: Equatable, Comparable {
|
||||
var loc = GridPoint(X: 0, Y: 0)
|
||||
var dir = Direction.up
|
||||
var intersection = Sequence.left
|
||||
var removed = false
|
||||
var dirValue: (Int, Int) {
|
||||
get {
|
||||
switch dir {
|
||||
case .up : return (0, -1)
|
||||
case .right: return (1, 0)
|
||||
case .down : return (0, 1)
|
||||
case .left : return (-1, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mutating func move() {
|
||||
loc.X = loc.X + dirValue.0
|
||||
loc.Y = loc.Y + dirValue.1
|
||||
}
|
||||
|
||||
mutating func changeDirection(with map: Character) {
|
||||
func rotateRight() { dir = Direction(rawValue: dir.rawValue + 1) ?? Direction.up }
|
||||
func rotateLeft() { dir = Direction(rawValue: dir.rawValue - 1) ?? Direction.left }
|
||||
func increaseSequence() { intersection = Sequence(rawValue: intersection.rawValue + 1) ?? Sequence.left }
|
||||
|
||||
if map == "-" || map == "|" { return }
|
||||
if map == "+" {
|
||||
switch intersection {
|
||||
case .left : rotateLeft()
|
||||
case .straight: break
|
||||
case .right : rotateRight()
|
||||
}
|
||||
increaseSequence()
|
||||
return
|
||||
}
|
||||
switch dir {
|
||||
case .up, .down :
|
||||
if map == "/" { rotateRight() }
|
||||
if map == "\\" { rotateLeft() }
|
||||
case .left, .right :
|
||||
if map == "/" { rotateLeft() }
|
||||
if map == "\\" { rotateRight() }
|
||||
}
|
||||
}
|
||||
|
||||
static func == (lhs: Cart, rhs: Cart) -> Bool {
|
||||
return (lhs.loc.X == rhs.loc.X) && (lhs.loc.Y == rhs.loc.Y)
|
||||
}
|
||||
|
||||
static func < (lhs: Cart, rhs: Cart) -> Bool {
|
||||
return lhs.loc.Y == rhs.loc.Y ? lhs.loc.X < rhs.loc.X : lhs.loc.Y < rhs.loc.Y
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Initialization:
|
||||
// 1. read in the grid to get the size (width anf height)
|
||||
// 2. convert to 2-dimensional grid of Character
|
||||
// 3. scan for carts
|
||||
// a. note the grid location
|
||||
// b. note the direction
|
||||
// c. initialize the "turning sequence" (count, direction)
|
||||
// d. convert the cart to the appropriate track
|
||||
// 1. '<' or '>' => '-'
|
||||
// 2. '^' or 'v' => '|'
|
||||
class Madness {
|
||||
var track: [[Character]] = []
|
||||
var width = 0
|
||||
var height = 0
|
||||
var carts: [Cart] = []
|
||||
|
||||
// Supply filename for input ex: '/home/peterr/AOC2018/Sources/AOC2018/data/day13.txt'
|
||||
init(withFile filename: String) {
|
||||
let trackFile = Tools.readFile(fromPath: filename)
|
||||
var trackStrings = trackFile.components(separatedBy: "\n")
|
||||
// This gurd statement is just an excuse to use guard
|
||||
// I'm assuming the last string is an empty string, if not DON'T remove the last string
|
||||
guard let lastStr = trackStrings.last, lastStr.count == 0 else { return }
|
||||
trackStrings.removeLast() // empty string
|
||||
parseData(withStars: trackStrings)
|
||||
}
|
||||
|
||||
// Supply test data in the form of a String
|
||||
init(withString trackFile: String) {
|
||||
let trackStrings = trackFile.components(separatedBy: "\n")
|
||||
parseData(withStars: trackStrings)
|
||||
}
|
||||
|
||||
func parseData(withStars trackArray: [String]) {
|
||||
guard trackArray.count > 0 else { print("Error Parsing"); return }
|
||||
width = trackArray[0].count
|
||||
height = trackArray.count
|
||||
for line in trackArray {
|
||||
track.append(Array(line))
|
||||
}
|
||||
|
||||
func newCart(at loc: (Int, Int), with direction: Direction) {
|
||||
carts.append(Cart(loc: GridPoint(X: loc.0, Y: loc.1), dir: direction, intersection: Sequence.left, removed: false))
|
||||
switch direction {
|
||||
case .up, .down : track[loc.1][loc.0] = "|"
|
||||
case .left, .right: track[loc.1][loc.0] = "-"
|
||||
}
|
||||
}
|
||||
|
||||
for j in 0..<height {
|
||||
for i in 0..<width {
|
||||
switch track[j][i] {
|
||||
case "^": newCart(at: (i, j), with: Direction.up)
|
||||
case "v": newCart(at: (i, j), with: Direction.down)
|
||||
case "<": newCart(at: (i, j), with: Direction.left)
|
||||
case ">": newCart(at: (i, j), with: Direction.right)
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getTrack(at loc: GridPoint) -> Character {
|
||||
guard loc.X >= 0 && loc.Y >= 0 && loc.X < width && loc.Y < height else { print("getTrack out of range"); return "#" }
|
||||
return track[loc.Y][loc.X]
|
||||
}
|
||||
|
||||
func collision(removeCrash: Bool) -> GridPoint? {
|
||||
var retVal: GridPoint? = nil
|
||||
var dupTest: [GridPoint : Int] = [:]
|
||||
for index in 0..<carts.count {
|
||||
if !carts[index].removed {
|
||||
if dupTest[carts[index].loc] != nil {
|
||||
if removeCrash {
|
||||
carts[index].removed = true
|
||||
carts[dupTest[carts[index].loc]!].removed = true
|
||||
} else {
|
||||
return carts[index].loc
|
||||
}
|
||||
} else {
|
||||
dupTest[carts[index].loc] = index
|
||||
}
|
||||
}
|
||||
}
|
||||
let notRemoved = carts.filter { $0.removed == false }
|
||||
if notRemoved.count == 1 {
|
||||
retVal = notRemoved[0].loc
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
// Start of Tick:
|
||||
// 1. order carts by location
|
||||
// 2. move cart one step in it's direction
|
||||
// 3. Look to see where we landed
|
||||
// a. other cart => CRASH
|
||||
// b. '-' or '|' is a straight track => do nothing
|
||||
// c. '\' => rotate right
|
||||
// d. '/' => rotate left
|
||||
// e. '+' => [Left, Straight, Right] sequense for this cart
|
||||
func tick(andRemove remove: Bool) -> GridPoint? {
|
||||
var collided: GridPoint? = nil
|
||||
carts.sort()
|
||||
for index in 0..<carts.count {
|
||||
if !carts[index].removed {
|
||||
carts[index].move()
|
||||
collided = collision(removeCrash: remove)
|
||||
if collided != nil && !remove {
|
||||
break
|
||||
}
|
||||
let track = getTrack(at: carts[index].loc)
|
||||
carts[index].changeDirection(with: track)
|
||||
}
|
||||
}
|
||||
return collided
|
||||
}
|
||||
}
|
||||
|
||||
class Day13: AOCDay {
|
||||
lazy var tests: (() -> ()) = day13Tests
|
||||
lazy var final: (() -> ()) = day13Final
|
||||
|
||||
let testData =
|
||||
"/->-\\ \n" +
|
||||
"| | /----\\\n" +
|
||||
"| /-+--+-\\ |\n" +
|
||||
"| | | | v |\n" +
|
||||
"\\-+-/ \\-+--/\n" +
|
||||
" \\------/ "
|
||||
|
||||
let testData2 =
|
||||
"/>-<\\ \n" +
|
||||
"| | \n" +
|
||||
"| /<+-\\\n" +
|
||||
"| | | v\n" +
|
||||
"\\>+</ |\n" +
|
||||
" | ^\n" +
|
||||
" \\<->/"
|
||||
|
||||
func testCartMove() {
|
||||
var car = Cart(loc: GridPoint(X: 10, Y:10), dir: Direction.up, intersection: Sequence.left, removed: false)
|
||||
car.move()
|
||||
XCTAssertEqual(test: "testCartMove", withExpression: (car.loc.X == 10 && car.loc.Y == 9))
|
||||
}
|
||||
|
||||
func testCartChangeDirection() {
|
||||
var car = Cart(loc: GridPoint(X: 10, Y:10), dir: Direction.up, intersection: Sequence.left, removed: false)
|
||||
car.move()
|
||||
car.changeDirection(with: "-")
|
||||
car.move()
|
||||
XCTAssertEqual(test: "testCartChangeDirection '-'", withExpression: (car.loc.X == 10 && car.loc.Y == 8))
|
||||
car.changeDirection(with: "|")
|
||||
car.move()
|
||||
XCTAssertEqual(test: "testCartChangeDirection '|'", withExpression: (car.loc.X == 10 && car.loc.Y == 7))
|
||||
car.changeDirection(with: "/")
|
||||
car.move()
|
||||
XCTAssertEqual(test: "testCartChangeDirection '/'", withExpression: (car.loc.X == 11 && car.loc.Y == 7))
|
||||
car.changeDirection(with: "\\")
|
||||
car.move()
|
||||
car.move()
|
||||
XCTAssertEqual(test: "testCartChangeDirection '\\'", withExpression: (car.loc.X == 11 && car.loc.Y == 9))
|
||||
car.changeDirection(with: "+")
|
||||
car.move()
|
||||
XCTAssertEqual(test: "testCartChangeDirection '+'", withExpression: (car.loc.X == 12 && car.loc.Y == 9))
|
||||
car.changeDirection(with: "+")
|
||||
car.move()
|
||||
XCTAssertEqual(test: "testCartChangeDirection '+'", withExpression: (car.loc.X == 13 && car.loc.Y == 9))
|
||||
car.changeDirection(with: "+")
|
||||
car.move()
|
||||
XCTAssertEqual(test: "testCartChangeDirection '+'", withExpression: (car.loc.X == 13 && car.loc.Y == 10))
|
||||
}
|
||||
|
||||
func testCartSort() {
|
||||
var cars: [Cart] = []
|
||||
cars.append(Cart(loc: GridPoint(X: 10, Y:10), dir: Direction.up, intersection: Sequence.left, removed: false))
|
||||
cars.append(Cart(loc: GridPoint(X: 5, Y:22), dir: Direction.up, intersection: Sequence.left, removed: false))
|
||||
cars.append(Cart(loc: GridPoint(X: 22, Y:5), dir: Direction.up, intersection: Sequence.left, removed: false))
|
||||
cars.append(Cart(loc: GridPoint(X: 2, Y:10), dir: Direction.up, intersection: Sequence.left, removed: false))
|
||||
cars.sort()
|
||||
let lastCar = cars.last!
|
||||
XCTAssertEqual(test: "testCartSort last", withExpression: (lastCar.loc.X == 5 && lastCar.loc.Y == 22))
|
||||
}
|
||||
|
||||
func testCartEquatable() {
|
||||
var car1 = Cart(loc: GridPoint(X: 10, Y:10), dir: Direction.up, intersection: Sequence.left, removed: false)
|
||||
car1.move()
|
||||
car1.changeDirection(with: "-")
|
||||
car1.move()
|
||||
let car2 = Cart(loc: GridPoint(X: 10, Y:8), dir: Direction.up, intersection: Sequence.left, removed: false)
|
||||
XCTAssertEqual(test: "testCartEquatable", withExpression: (car1 == car2))
|
||||
}
|
||||
|
||||
func testMadnessInit() {
|
||||
let mad = Madness(withString: testData)
|
||||
printTrack(with: mad)
|
||||
XCTAssertEqual(test: "testMadnessInit string", withExpression: (mad.width == 13 && mad.height == 6))
|
||||
if mad.carts.count != 2 {
|
||||
XCTAssertEqual(test: "testMadnessInit carts count", withExpression: (false))
|
||||
} else {
|
||||
XCTAssertEqual(test: "testMadnessInit carts count", withExpression: (mad.carts.count == 2))
|
||||
XCTAssertEqual(test: "testMadnessInit cart X", withExpression: (mad.carts[0].loc.X == 2))
|
||||
XCTAssertEqual(test: "testMadnessInit cart Y", withExpression: (mad.carts[0].loc.Y == 0))
|
||||
XCTAssertEqual(test: "testMadnessInit cart direction", withExpression: (mad.carts[0].dir == Direction.right))
|
||||
}
|
||||
}
|
||||
|
||||
func testGetTrack() {
|
||||
let mad = Madness(withString: testData)
|
||||
var result = mad.getTrack(at: GridPoint(X: 4, Y: 2))
|
||||
XCTAssertEqual(test: "testGetTrack (5, 3)", withExpression: (result == "+"))
|
||||
result = mad.getTrack(at: GridPoint(X: 2, Y: 0))
|
||||
XCTAssertEqual(test: "testGetTrack (3, 1) convert cart to track", withExpression: (result == "-"))
|
||||
}
|
||||
|
||||
func testCollision() {
|
||||
let mad = Madness(withString: testData)
|
||||
mad.carts[1].loc = mad.carts[0].loc
|
||||
XCTAssertEqual(test: "testCollision", withExpression: (mad.collision(removeCrash: false) != nil))
|
||||
}
|
||||
|
||||
func testTick() {
|
||||
let mad = Madness(withString: testData)
|
||||
let oldcart = mad.carts[0]
|
||||
let collided = mad.tick(andRemove: false)
|
||||
let newcart = mad.carts[0]
|
||||
XCTAssertEqual(test: "testTick", withExpression: (oldcart != newcart))
|
||||
XCTAssertEqual(test: "testTick", withExpression: (collided == nil))
|
||||
}
|
||||
|
||||
func printTrack(with mad: Madness) {
|
||||
func cartLoc(at loc: GridPoint) -> (Bool, Character) {
|
||||
var retVal: (Bool, Character) = (false, " ")
|
||||
for cart in mad.carts {
|
||||
if cart.loc == loc && !cart.removed{
|
||||
switch cart.dir {
|
||||
case .up : retVal = (true, "^")
|
||||
case .down : retVal = (true, "v")
|
||||
case .left : retVal = (true, "<")
|
||||
case .right: retVal = (true, ">")
|
||||
}
|
||||
}
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
for j in 0..<mad.height {
|
||||
for i in 0..<mad.width {
|
||||
let cartIcon = cartLoc(at: GridPoint(X: i, Y: j))
|
||||
if cartIcon.0 {
|
||||
print("\(cartIcon.1)", terminator: " ")
|
||||
} else {
|
||||
print("\(mad.getTrack(at: GridPoint(X: i, Y: j)))", terminator: " ")
|
||||
}
|
||||
}
|
||||
print("")
|
||||
}
|
||||
print("")
|
||||
}
|
||||
|
||||
func testRun() {
|
||||
var mad = Madness(withString: testData)
|
||||
printTrack(with: mad)
|
||||
var crash: GridPoint?
|
||||
repeat {
|
||||
crash = mad.tick(andRemove: false)
|
||||
} while crash == nil
|
||||
// print("Collision location Part1: (\(crash!))")
|
||||
XCTAssertEqual(test: "testRun Part 1", withExpression: (crash! == GridPoint(X: 7, Y: 3)))
|
||||
|
||||
mad = Madness(withString: testData2)
|
||||
printTrack(with: mad)
|
||||
repeat {
|
||||
crash = mad.tick(andRemove: true)
|
||||
} while crash == nil
|
||||
// print("Last Cart location Part2: (\(crash!))")
|
||||
XCTAssertEqual(test: "testRun Part 2", withExpression: (crash! == GridPoint(X: 6, Y: 4)))
|
||||
}
|
||||
|
||||
func day13Tests() {
|
||||
testCartMove()
|
||||
testCartChangeDirection()
|
||||
testCartSort()
|
||||
testCartEquatable()
|
||||
testMadnessInit()
|
||||
testGetTrack()
|
||||
testCollision()
|
||||
testTick()
|
||||
testRun()
|
||||
}
|
||||
|
||||
func day13Final() {
|
||||
var mad = Madness(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day13.txt")
|
||||
var crash: GridPoint?
|
||||
repeat {
|
||||
crash = mad.tick(andRemove: false)
|
||||
} while crash == nil
|
||||
print("Answer to part 1 is: \(crash!)")
|
||||
|
||||
mad = Madness(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day13.txt")
|
||||
repeat {
|
||||
crash = mad.tick(andRemove: true)
|
||||
} while crash == nil
|
||||
print("Answer to part 2 is: \(crash!)")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
//
|
||||
// Advent of Code 2018 "Day 14: Chocolate Charts"
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class Chocolate {
|
||||
var score: [Int] = [3, 7, 1, 0]
|
||||
var scoreStr = "3710"
|
||||
var elf: [Int] = [0, 1]
|
||||
var lf2 = 3
|
||||
|
||||
func moveForward() {
|
||||
for index in 0..<elf.count {
|
||||
let currentRecipe = elf[index]
|
||||
let moveCount = score[elf[index]] + 1
|
||||
elf[index] = moveCount + currentRecipe
|
||||
if elf[index] >= score.count {
|
||||
elf[index] -= score.count
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func nextRecipe() {
|
||||
var sum = 0
|
||||
for index in 0..<elf.count {
|
||||
sum += score[elf[index]]
|
||||
}
|
||||
let strsum = Array(String(sum))
|
||||
for i in 0..<strsum.count {
|
||||
let newScore = String(strsum[i])
|
||||
score.append(Int(newScore)!)
|
||||
scoreStr += newScore
|
||||
}
|
||||
}
|
||||
|
||||
func get10RecipeScore(after index: Int) -> String {
|
||||
var retVal = ""
|
||||
repeat {
|
||||
nextRecipe()
|
||||
moveForward()
|
||||
} while score.count < index+10
|
||||
for i in index..<index+10 {
|
||||
retVal += String(score[i])
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func getNumBefore(pattern: String) -> Int {
|
||||
var distance = 0
|
||||
let range = scoreStr.range(of: pattern)
|
||||
if let range = range {
|
||||
distance = scoreStr.distance(from: scoreStr.startIndex, to: range.lowerBound)
|
||||
}
|
||||
return distance
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Day14: AOCDay {
|
||||
lazy var tests: (() -> ()) = day14Tests
|
||||
lazy var final: (() -> ()) = day14Final
|
||||
|
||||
func testNextRecipe() {
|
||||
let cho = Chocolate()
|
||||
cho.nextRecipe()
|
||||
guard cho.score.count == 6 else {
|
||||
XCTAssertEqual(test: "testNextRecipe fail count", withExpression: (false))
|
||||
return
|
||||
}
|
||||
XCTAssertEqual(test: "testNextRecipe", withExpression: (cho.score[4] == 1 && cho.score[5] == 0))
|
||||
}
|
||||
|
||||
func testMoveForward() {
|
||||
let cho = Chocolate()
|
||||
cho.nextRecipe()
|
||||
cho.moveForward()
|
||||
XCTAssertEqual(test: "testMoveForward", withExpression: (cho.elf[0] == 4 && cho.elf[1] == 3))
|
||||
}
|
||||
|
||||
func testGet10RecipeScore() {
|
||||
var cho = Chocolate()
|
||||
var answer = cho.get10RecipeScore(after: 9)
|
||||
XCTAssertEqual(test: "testGet10RecipeScore 9", withExpression: (answer == "5158916779"))
|
||||
cho = Chocolate()
|
||||
answer = cho.get10RecipeScore(after: 5)
|
||||
XCTAssertEqual(test: "testGet10RecipeScore 5", withExpression: (answer == "0124515891"))
|
||||
cho = Chocolate()
|
||||
answer = cho.get10RecipeScore(after: 18)
|
||||
XCTAssertEqual(test: "testGet10RecipeScore 18", withExpression: (answer == "9251071085"))
|
||||
cho = Chocolate()
|
||||
answer = cho.get10RecipeScore(after: 2018)
|
||||
XCTAssertEqual(test: "testGet10RecipeScore 2018", withExpression: (answer == "5941429882"))
|
||||
}
|
||||
|
||||
func testGetNumBefore() {
|
||||
let cho = Chocolate()
|
||||
_ = cho.get10RecipeScore(after: 2018)
|
||||
var answer = cho.getNumBefore(pattern: "51589")
|
||||
XCTAssertEqual(test: "testGetNumBefore 51589", withExpression: (answer == 9))
|
||||
answer = cho.getNumBefore(pattern: "01245")
|
||||
XCTAssertEqual(test: "testGetNumBefore 01245", withExpression: (answer == 5))
|
||||
answer = cho.getNumBefore(pattern: "92510")
|
||||
XCTAssertEqual(test: "testGetNumBefore 92510", withExpression: (answer == 18))
|
||||
answer = cho.getNumBefore(pattern: "59414")
|
||||
XCTAssertEqual(test: "testGetNumBefore 59414", withExpression: (answer == 2018))
|
||||
}
|
||||
|
||||
func day14Tests() {
|
||||
testNextRecipe()
|
||||
testMoveForward()
|
||||
testGet10RecipeScore()
|
||||
testGetNumBefore()
|
||||
}
|
||||
|
||||
func day14Final() {
|
||||
let cho = Chocolate()
|
||||
let answer = cho.get10RecipeScore(after: 580741)
|
||||
print("Answer to part 1 is: \(answer)")
|
||||
// let answer = cho.get10RecipeScore(after: 112580741)
|
||||
// let dist = cho.getNumBefore(pattern: "580741")
|
||||
// print("Answer to part 2 is: \(dist)")
|
||||
print("Brute forced part 2 - takes too long")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,789 @@
|
||||
//
|
||||
// Advent of Code 2018 "Day 15: Beverage Bandits"
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum State: Int {
|
||||
case Unknown = -4
|
||||
case Wall = -3
|
||||
case Open = 0
|
||||
case Elf = 1
|
||||
case Goblin = 2
|
||||
}
|
||||
|
||||
struct Entity: Equatable, Comparable {
|
||||
var kind: State
|
||||
var loc: GridPoint
|
||||
var power: Int
|
||||
var hitPts: Int
|
||||
|
||||
init(kind: State, loc: GridPoint, power: Int = 3, hitPts: Int = 200) {
|
||||
self.kind = kind
|
||||
self.loc = loc
|
||||
self.power = power
|
||||
self.hitPts = hitPts
|
||||
}
|
||||
static func == (lhs: Entity, rhs: Entity) -> Bool {
|
||||
return (lhs.loc == rhs.loc) && (lhs.power == rhs.power) && (lhs.hitPts == rhs.hitPts)
|
||||
}
|
||||
|
||||
static func < (lhs: Entity, rhs: Entity) -> Bool {
|
||||
return lhs.loc < rhs.loc
|
||||
}
|
||||
}
|
||||
|
||||
class Beverage {
|
||||
var entities: [Entity] = []
|
||||
var maze: [[Character]] = []
|
||||
var nummaze: [[State]] = []
|
||||
var entityDict: [GridPoint : Int] = [:]
|
||||
var width = 0
|
||||
var height = 0
|
||||
var rounds = 0
|
||||
|
||||
// Supply filename for input ex: '/home/peterr/AOC2018/Sources/AOC2018/data/day15.txt'
|
||||
init(withFile filename: String) {
|
||||
let mazeFile = Tools.readFile(fromPath: filename)
|
||||
var mazeStrings = mazeFile.components(separatedBy: "\n")
|
||||
// This gurd statement is just an excuse to use guard
|
||||
// I'm assuming the last string is an empty string, if not DON'T remove the last string
|
||||
guard let lastStr = mazeStrings.last, lastStr.count == 0 else { return }
|
||||
mazeStrings.removeLast() // empty string
|
||||
parseData(intoGrid: mazeStrings)
|
||||
}
|
||||
|
||||
// Supply test data in the form of a String
|
||||
init(withString mazeFile: String) {
|
||||
let mazeStrings = mazeFile.components(separatedBy: "\n")
|
||||
parseData(intoGrid: mazeStrings)
|
||||
}
|
||||
|
||||
func parseData(intoGrid mazeArray: [String]) {
|
||||
guard mazeArray.count > 0 else { print("Error Parsing"); return }
|
||||
width = mazeArray[0].count
|
||||
height = mazeArray.count
|
||||
for line in mazeArray {
|
||||
maze.append(Array(line))
|
||||
}
|
||||
|
||||
func newEntity(type kind: State, at loc: (Int, Int)) {
|
||||
var power = 3
|
||||
if kind == .Elf {
|
||||
power = 12
|
||||
}
|
||||
entities.append(Entity(kind: kind, loc: GridPoint(X: loc.0, Y: loc.1), power: power))
|
||||
}
|
||||
|
||||
for _ in 0..<height {
|
||||
nummaze.append(Array(repeating: .Wall, count: width))
|
||||
}
|
||||
|
||||
for j in 0..<height {
|
||||
for i in 0..<width {
|
||||
switch maze[j][i] {
|
||||
case "#": break // we initialized this grid to all "walls"
|
||||
case ".": nummaze[j][i] = .Open
|
||||
case "G": nummaze[j][i] = .Goblin
|
||||
newEntity(type: .Goblin,at: (i, j))
|
||||
case "E": nummaze[j][i] = .Elf
|
||||
newEntity(type: .Elf, at: (i, j))
|
||||
default: nummaze[j][i] = .Unknown
|
||||
}
|
||||
}
|
||||
}
|
||||
updateEntityDict()
|
||||
entities.sort()
|
||||
}
|
||||
|
||||
func updateEntityDict() {
|
||||
entityDict = [:]
|
||||
for index in 0..<entities.count {
|
||||
if entities[index].hitPts > 0 {
|
||||
entityDict[entities[index].loc] = index
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the entities (reading order) and repopulate the nummaze map
|
||||
func updateMaze() {
|
||||
for j in 0..<height {
|
||||
for i in 0..<width {
|
||||
if nummaze[j][i] == .Elf || nummaze[j][i] == .Goblin {
|
||||
nummaze[j][i] = .Open
|
||||
}
|
||||
}
|
||||
}
|
||||
for entity in entities {
|
||||
if entity.hitPts > 0 {
|
||||
switch entity.kind {
|
||||
case .Elf: nummaze[entity.loc.Y][entity.loc.X] = .Elf
|
||||
case .Goblin: nummaze[entity.loc.Y][entity.loc.X] = .Goblin
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func printMaze(with maze: [[Int]]) {
|
||||
let width = maze[0].count
|
||||
let height = maze.count
|
||||
|
||||
for j in 0..<height {
|
||||
for i in 0..<width {
|
||||
switch maze[j][i] {
|
||||
case -4: print("?", terminator: "")
|
||||
case -3: print("#", terminator: "")
|
||||
case -2: print("G", terminator: "")
|
||||
case -1: print("E", terminator: "")
|
||||
case 0: print(".", terminator: "")
|
||||
default: print("\(maze[j][i])", terminator: "")
|
||||
}
|
||||
}
|
||||
print("")
|
||||
}
|
||||
print("")
|
||||
}
|
||||
|
||||
// Return the distance and the preferred direction (direction only valid by reversing the request; i.e. swapping orig and dest)
|
||||
func distance(from origin: GridPoint, to dest: GridPoint) -> (dist: Int, dir: GridPoint) {
|
||||
var retVal = (dist: -1, dir: GridPoint(X:0, Y:0))
|
||||
var distMaze: [[Int]] = []
|
||||
for row in nummaze {
|
||||
distMaze.append(row.map { if $0.rawValue > 0 { return -$0.rawValue } else { return $0.rawValue } })
|
||||
}
|
||||
func testAndQueue(for point: GridPoint, on wave: Int, in queue: inout [GridPoint]) {
|
||||
if distMaze[point.Y][point.X] == 0 {
|
||||
distMaze[point.Y][point.X] = wave
|
||||
queue.append(point)
|
||||
}
|
||||
}
|
||||
|
||||
var wave = 1
|
||||
var done = false
|
||||
var queue: [GridPoint] = [origin]
|
||||
distMaze[dest.Y][dest.X] = 0
|
||||
while !done {
|
||||
var newQueue: [GridPoint] = []
|
||||
for point in queue {
|
||||
testAndQueue(for: point.up, on: wave, in: &newQueue)
|
||||
testAndQueue(for: point.down, on: wave, in: &newQueue)
|
||||
testAndQueue(for: point.left, on: wave, in: &newQueue)
|
||||
testAndQueue(for: point.right, on: wave, in: &newQueue)
|
||||
}
|
||||
queue = newQueue
|
||||
if queue.contains(dest) {
|
||||
done = true
|
||||
retVal.dist = distMaze[dest.Y][dest.X]
|
||||
if wave == 1 {
|
||||
retVal.dir = origin - dest
|
||||
}
|
||||
}
|
||||
done = done || (newQueue.count == 0)
|
||||
wave += 1
|
||||
}
|
||||
// printMaze(with: distMaze)
|
||||
|
||||
// Determin direction by locating the lowest distance count via reading-order
|
||||
if retVal.dir == GridDir.none {
|
||||
if distMaze[dest.up.Y][dest.up.X] == retVal.dist-1 {
|
||||
retVal.dir = GridDir.up
|
||||
} else if distMaze[dest.left.Y][dest.left.X] == retVal.dist-1 {
|
||||
retVal.dir = GridDir.left
|
||||
} else if distMaze[dest.right.Y][dest.right.X] == retVal.dist-1 {
|
||||
retVal.dir = GridDir.right
|
||||
} else if distMaze[dest.down.Y][dest.down.X] == retVal.dist-1 {
|
||||
retVal.dir = GridDir.down
|
||||
}
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func findNearestTarget(for attacker: Entity) -> GridPoint {
|
||||
var retVal = GridPoint(X: -1, Y: -1)
|
||||
var list: [GridPoint : Bool] = [:]
|
||||
func testAnAddToList(for point: GridPoint) {
|
||||
if nummaze[point.Y][point.X] == .Open {
|
||||
list[point] = true
|
||||
}
|
||||
}
|
||||
|
||||
// Create a list of reachables
|
||||
for entity in entities {
|
||||
if entity.hitPts > 0 && entity.kind == enemy(of: attacker) {
|
||||
testAnAddToList(for: entity.loc.up)
|
||||
testAnAddToList(for: entity.loc.down)
|
||||
testAnAddToList(for: entity.loc.left)
|
||||
testAnAddToList(for: entity.loc.right)
|
||||
}
|
||||
}
|
||||
let inRange = Array(list.keys)
|
||||
var reachable: [GridPoint : Int] = [:]
|
||||
|
||||
// Create a sorted list of Nearest targets from reachables
|
||||
var minDist = width + height
|
||||
for target in inRange {
|
||||
let dist = distance(from: attacker.loc, to: target).dist
|
||||
if dist > 0 {
|
||||
minDist = min(dist, minDist)
|
||||
reachable[target] = dist
|
||||
}
|
||||
}
|
||||
var nearest = Array(reachable.filter { $0.value == minDist }.keys)
|
||||
nearest.sort()
|
||||
if nearest.count > 0 {
|
||||
retVal = nearest[0]
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func moveDirection(from entity: Entity, to dest: GridPoint) -> GridPoint {
|
||||
// use the reverse map in 'distance' to come up with a preferred direction
|
||||
var retVal = GridPoint(X:0,Y:0)
|
||||
if dest != GridPoint(X: -1, Y: -1) {
|
||||
let dist = distance(from: dest, to: entity.loc)
|
||||
if dist.dist > 0 {
|
||||
retVal = dist.dir
|
||||
}
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func round() -> Bool {
|
||||
var done = false
|
||||
// Only sort once per round
|
||||
entities.sort()
|
||||
for index in 0..<entities.count {
|
||||
if entities[index].hitPts > 0 {
|
||||
done = takeTurn(with: index)
|
||||
if done {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if !done {
|
||||
rounds += 1
|
||||
}
|
||||
return done
|
||||
}
|
||||
|
||||
func tabulateScore() -> Int {
|
||||
// sum remaining hitPts
|
||||
var sum = 0
|
||||
for entity in entities {
|
||||
if entity.hitPts > 0 {
|
||||
sum += entity.hitPts
|
||||
}
|
||||
}
|
||||
return sum * rounds
|
||||
}
|
||||
|
||||
let watchIndex = -1
|
||||
|
||||
|
||||
func takeTurn(with entityIndex: Int) -> Bool {
|
||||
//done test
|
||||
let viableEnemy = entities.filter { $0.kind == enemy(of: entities[entityIndex]) && $0.hitPts > 0 }
|
||||
guard viableEnemy.count > 0 else { return true }
|
||||
|
||||
// entityDict must be updated for every action (move or attack)
|
||||
updateEntityDict()
|
||||
// Adjacent to target?
|
||||
var indexOfAdjeacentTarget = adjacent(to: entityIndex)
|
||||
if indexOfAdjeacentTarget == -1 {
|
||||
// find nearest enemy
|
||||
let nearest = findNearestTarget(for: entities[entityIndex])
|
||||
// determine direction to go
|
||||
let direction = moveDirection(from: entities[entityIndex], to: nearest)
|
||||
// print("nearest \(nearest), direction = \(direction)")
|
||||
// move and update dict and map
|
||||
entities[entityIndex].loc = entities[entityIndex].loc + direction
|
||||
if entityIndex == watchIndex {
|
||||
print("\(entities[entityIndex])")
|
||||
print("nearest : \(nearest)")
|
||||
print("direction : \(direction)")
|
||||
}
|
||||
updateEntityDict()
|
||||
updateMaze()
|
||||
}
|
||||
// Check if we moved within range
|
||||
indexOfAdjeacentTarget = adjacent(to: entityIndex)
|
||||
if entityIndex == watchIndex && indexOfAdjeacentTarget > 0 {
|
||||
print("adjacent Target : \(entities[indexOfAdjeacentTarget])")
|
||||
}
|
||||
if indexOfAdjeacentTarget != -1 {
|
||||
attack(from: entities[entityIndex], to: indexOfAdjeacentTarget)
|
||||
updateEntityDict()
|
||||
updateMaze()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func enemy(of entity: Entity) -> State {
|
||||
var retVal = State.Goblin
|
||||
if entity.kind == .Goblin {
|
||||
retVal = .Elf
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
// Return the index number of the target to attack (or -1 if no target)
|
||||
func adjacent(to subjectIndex: Int) -> Int {
|
||||
var retVal = -1
|
||||
var enemyDict: [GridPoint:Int] = [:] // Loc : HitPts
|
||||
|
||||
func determineEnemyAndQueue(for loc: GridPoint) {
|
||||
if nummaze[loc.Y][loc.X] == enemy(of: entities[subjectIndex]) {
|
||||
updateEntityDict()
|
||||
if let index = entityDict[loc] {
|
||||
enemyDict[loc] = entities[index].hitPts
|
||||
}
|
||||
}
|
||||
}
|
||||
// create list of adjacent enemies
|
||||
determineEnemyAndQueue(for: entities[subjectIndex].loc.up)
|
||||
determineEnemyAndQueue(for: entities[subjectIndex].loc.left)
|
||||
determineEnemyAndQueue(for: entities[subjectIndex].loc.right)
|
||||
determineEnemyAndQueue(for: entities[subjectIndex].loc.down)
|
||||
|
||||
// sort list by HitPoints, fewest to most order
|
||||
if enemyDict.count > 0 {
|
||||
// find min hit point
|
||||
let minHP = enemyDict.min { a, b in a.value < b.value }?.value ?? -1
|
||||
// gather array of min-hitpoint enemies
|
||||
let minDict = enemyDict.filter {$0.value == minHP}
|
||||
// sort enemies by location in reading-order
|
||||
let enemy = minDict.sorted(by: <)
|
||||
// select the first one
|
||||
retVal = entityDict[enemy[0].key]!
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func attack(from attacker: Entity, to victimIndex: Int) {
|
||||
entities[victimIndex].hitPts = entities[victimIndex].hitPts - attacker.power
|
||||
// print("attacker power = \(attacker.power)")
|
||||
if entities[victimIndex].hitPts <= 0 && entities[victimIndex].kind == .Elf {
|
||||
print("Fail")
|
||||
while true {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
class Day15: AOCDay {
|
||||
lazy var tests: (() -> ()) = day15Tests
|
||||
lazy var final: (() -> ()) = day15Final
|
||||
|
||||
let testData1 = """
|
||||
#######
|
||||
#E..G.#
|
||||
#...#.#
|
||||
#.G.#G#
|
||||
#######
|
||||
"""
|
||||
|
||||
let testData2 = """
|
||||
#######
|
||||
#.E...#
|
||||
#.....#
|
||||
#...G.#
|
||||
#######
|
||||
"""
|
||||
|
||||
let testData3 = """
|
||||
#########
|
||||
#G.....G#
|
||||
#...G...#
|
||||
#...E...#
|
||||
#G.....G#
|
||||
#.......#
|
||||
#.......#
|
||||
#G..G..G#
|
||||
#########
|
||||
"""
|
||||
|
||||
let testData4 = """
|
||||
#########
|
||||
#G..G..G#
|
||||
#.......#
|
||||
#.......#
|
||||
#G..E..G#
|
||||
#.......#
|
||||
#.......#
|
||||
#G..G..G#
|
||||
#########
|
||||
"""
|
||||
|
||||
let testData5 = """
|
||||
#######
|
||||
#...G.#
|
||||
#..G.G#
|
||||
#.#.#G#
|
||||
#...#E#
|
||||
#.....#
|
||||
#######
|
||||
"""
|
||||
|
||||
let testData6 = """
|
||||
#######
|
||||
#G....#
|
||||
#..G..#
|
||||
#..EG.#
|
||||
#..G..#
|
||||
#...G.#
|
||||
#######
|
||||
"""
|
||||
|
||||
|
||||
let testData7 = """
|
||||
#######
|
||||
#.G...#
|
||||
#...EG#
|
||||
#.#.#G#
|
||||
#..G#E#
|
||||
#.....#
|
||||
#######
|
||||
"""
|
||||
|
||||
// Combat ends after 37 full rounds
|
||||
// Elves win with 982 total hit points left
|
||||
// Outcome: 37 * 982 = 36334
|
||||
let testData8 = """
|
||||
#######
|
||||
#G..#E#
|
||||
#E#E.E#
|
||||
#G.##.#
|
||||
#...#E#
|
||||
#...E.#
|
||||
#######
|
||||
"""
|
||||
|
||||
// Combat ends after 46 full rounds
|
||||
// Elves win with 859 total hit points left
|
||||
// Outcome: 46 * 859 = 39514
|
||||
let testData9 = """
|
||||
#######
|
||||
#E..EG#
|
||||
#.#G.E#
|
||||
#E.##E#
|
||||
#G..#.#
|
||||
#..E#.#
|
||||
#######
|
||||
"""
|
||||
|
||||
// Combat ends after 35 full rounds
|
||||
// Goblins win with 793 total hit points left
|
||||
// Outcome: 35 * 793 = 27755
|
||||
let testData10 = """
|
||||
#######
|
||||
#E.G#.#
|
||||
#.#G..#
|
||||
#G.#.G#
|
||||
#G..#.#
|
||||
#...E.#
|
||||
#######
|
||||
"""
|
||||
|
||||
// Combat ends after 54 full rounds
|
||||
// Goblins win with 536 total hit points left
|
||||
// Outcome: 54 * 536 = 28944
|
||||
let testData11 = """
|
||||
#######
|
||||
#.E...#
|
||||
#.#..G#
|
||||
#.###.#
|
||||
#E#G#G#
|
||||
#...#G#
|
||||
#######
|
||||
"""
|
||||
|
||||
// Combat ends after 20 full rounds
|
||||
// Goblins win with 937 total hit points left
|
||||
// Outcome: 20 * 937 = 18740
|
||||
let testData12 = """
|
||||
#########
|
||||
#G......#
|
||||
#.E.#...#
|
||||
#..##..G#
|
||||
#...##..#
|
||||
#...#...#
|
||||
#.G...G.#
|
||||
#.....G.#
|
||||
#########
|
||||
"""
|
||||
|
||||
func testInitFile() {
|
||||
let bev = Beverage(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day15.txt")
|
||||
printMaze(with: bev)
|
||||
}
|
||||
|
||||
func testInitString() {
|
||||
let bev = Beverage(withString: testData1)
|
||||
printMaze(with: bev)
|
||||
}
|
||||
|
||||
func testEntities() {
|
||||
let bev = Beverage(withString: testData1)
|
||||
var myentities = bev.entities
|
||||
func show(entities: [Entity]) {
|
||||
var id = 0
|
||||
for entity in entities {
|
||||
print("\(id) : \(entity)")
|
||||
id += 1
|
||||
}
|
||||
}
|
||||
// show(entities: myentities) // Demonstrated that sorting works when force-read in the entities in reversse order
|
||||
myentities.sort()
|
||||
// show(entities: myentities)
|
||||
}
|
||||
|
||||
func testFindNearestTarget() {
|
||||
var bev = Beverage(withString: testData1)
|
||||
var nearest = bev.findNearestTarget(for: bev.entities[0])
|
||||
XCTAssertEqual(test: "testFindNearestTarget (Elf)", withExpression: (nearest == GridPoint(X: 3, Y: 1)))
|
||||
nearest = bev.findNearestTarget(for: bev.entities[1])
|
||||
XCTAssertEqual(test: "testFindNearestTarget (Goblin 0)", withExpression: (nearest == GridPoint(X: 2, Y: 1)))
|
||||
nearest = bev.findNearestTarget(for: bev.entities[2])
|
||||
XCTAssertEqual(test: "testFindNearestTarget (Goblin 1)", withExpression: (nearest == GridPoint(X: 2, Y: 1)))
|
||||
nearest = bev.findNearestTarget(for: bev.entities[3])
|
||||
XCTAssertEqual(test: "testFindNearestTarget (Goblin 2)", withExpression: (nearest == GridPoint(X: -1, Y: -1)))
|
||||
|
||||
bev = Beverage(withString: testData5)
|
||||
nearest = bev.findNearestTarget(for: bev.entities[3])
|
||||
XCTAssertEqual(test: "testFindNearestTarget is Goblin", withExpression: (bev.entities[3].kind == .Goblin))
|
||||
XCTAssertEqual(test: "testFindNearestTarget is Elf", withExpression: (bev.entities[4].kind == .Elf))
|
||||
XCTAssertEqual(test: "testFindNearestTarget (Goblin)", withExpression: (nearest == GridPoint(X: 3, Y: 3)))
|
||||
}
|
||||
|
||||
func testDistance() {
|
||||
let bev = Beverage(withString: testData1)
|
||||
var dist = bev.distance(from: bev.entities[0].loc, to: GridPoint(X: 2, Y: 2)).dist
|
||||
XCTAssertEqual(test: "testDistance (2, 2) = 2", withExpression: (dist == 2))
|
||||
dist = bev.distance(from: bev.entities[0].loc, to: GridPoint(X: 5, Y: 2)).dist
|
||||
XCTAssertEqual(test: "testDistance (5, 2) = -1", withExpression: (dist == -1))
|
||||
dist = bev.distance(from: bev.entities[0].loc, to: GridPoint(X: 2, Y: 1)).dist
|
||||
XCTAssertEqual(test: "testDistance (2, 1) = 0", withExpression: (dist == 1))
|
||||
dist = bev.distance(from: bev.entities[3].loc, to: GridPoint(X: 2, Y: 1)).dist
|
||||
XCTAssertEqual(test: "testDistance last Goblin to` Elf", withExpression: (dist == -1))
|
||||
}
|
||||
|
||||
func testMoveDirection() {
|
||||
var bev = Beverage(withString: testData1)
|
||||
var nearest = bev.findNearestTarget(for: bev.entities[0])
|
||||
var direction = bev.moveDirection(from: bev.entities[0], to: nearest)
|
||||
XCTAssertEqual(test: "testMoveDirection testData1", withExpression: (direction == GridDir.right))
|
||||
bev = Beverage(withString: testData2)
|
||||
nearest = bev.findNearestTarget(for: bev.entities[0])
|
||||
direction = bev.moveDirection(from: bev.entities[0], to: nearest)
|
||||
XCTAssertEqual(test: "testMoveDirection testData2", withExpression: (direction == GridDir.right))
|
||||
|
||||
bev = Beverage(withString: testData5)
|
||||
nearest = bev.findNearestTarget(for: bev.entities[1])
|
||||
direction = bev.moveDirection(from: bev.entities[1], to: nearest)
|
||||
print("Nearest: \(nearest)")
|
||||
print("Direction: \(direction)")
|
||||
XCTAssertEqual(test: "testMoveDirection is Goblin", withExpression: (bev.entities[1].kind == .Goblin))
|
||||
XCTAssertEqual(test: "testMoveDirection is Elf", withExpression: (bev.entities[4].kind == .Elf))
|
||||
XCTAssertEqual(test: "testMoveDirection (nearest)", withExpression: (nearest == GridPoint(X: 5, Y: 5)))
|
||||
XCTAssertEqual(test: "testMoveDirection (dir)", withExpression: (direction == GridDir.down))
|
||||
}
|
||||
|
||||
func testAdjacent() {
|
||||
var bev = Beverage(withString: testData3)
|
||||
var adjacent = bev.adjacent(to: 3)
|
||||
XCTAssertEqual(test: "testAdjacent is Elf", withExpression: (bev.entities[3].kind == .Elf))
|
||||
XCTAssertEqual(test: "testAdjacent is adjacent", withExpression: (adjacent == 2))
|
||||
bev = Beverage(withString: testData4)
|
||||
adjacent = bev.adjacent(to: 4)
|
||||
XCTAssertEqual(test: "testAdjacent is Elf", withExpression: (bev.entities[4].kind == .Elf))
|
||||
XCTAssertEqual(test: "testAdjacent is not adjacent", withExpression: (adjacent == -1))
|
||||
}
|
||||
|
||||
func testTakeTurn() {
|
||||
var bev = Beverage(withString: testData3)
|
||||
XCTAssertEqual(test: "testTakeTurn is Elf", withExpression: (bev.entities[3].kind == .Elf))
|
||||
// printMaze(with: bev)
|
||||
_ = bev.takeTurn(with: 3)
|
||||
// printMaze(with: bev)
|
||||
bev = Beverage(withString: testData4)
|
||||
XCTAssertEqual(test: "testTakeTurn is Elf", withExpression: (bev.entities[4].kind == .Elf))
|
||||
// printMaze(with: bev)
|
||||
_ = bev.takeTurn(with: 4)
|
||||
// printMaze(with: bev)
|
||||
}
|
||||
|
||||
func testAttack() {
|
||||
let bev = Beverage(withString: testData6)
|
||||
// G.... 9 G.... 9
|
||||
// ..G.. 4 ..G.. 4
|
||||
// ..EG. 2 --> ..E..
|
||||
// ..G.. 2 ..G.. 2
|
||||
// ...G. 1 ...G. 1
|
||||
bev.entities[0].hitPts = 9
|
||||
bev.entities[1].hitPts = 4
|
||||
bev.entities[3].hitPts = 2
|
||||
bev.entities[4].hitPts = 2
|
||||
bev.entities[5].hitPts = 1
|
||||
printMaze(with: bev, withHP: true)
|
||||
let indexOfAdjeacentTarget = bev.adjacent(to: 2)
|
||||
if indexOfAdjeacentTarget != -1 {
|
||||
bev.attack(from: bev.entities[2], to: indexOfAdjeacentTarget)
|
||||
bev.updateEntityDict()
|
||||
bev.updateMaze()
|
||||
}
|
||||
printMaze(with: bev, withHP: true)
|
||||
}
|
||||
|
||||
func testRound() {
|
||||
let bev = Beverage(withString: testData4)
|
||||
// printMaze(with: bev)
|
||||
_ = bev.round()
|
||||
// printMaze(with: bev)
|
||||
_ = bev.round()
|
||||
// printMaze(with: bev)
|
||||
_ = bev.round()
|
||||
printMaze(with: bev)
|
||||
let adjacent = bev.adjacent(to: 4)
|
||||
// print("adjacent=\(adjacent)")
|
||||
// print("entity = \(bev.entities[adjacent])")
|
||||
XCTAssertEqual(test: "testRound is Elf", withExpression: (bev.entities[4].kind == .Elf))
|
||||
XCTAssertEqual(test: "testRound attack entity 1", withExpression: (bev.entities[adjacent].loc == GridPoint(X: 4, Y: 2)))
|
||||
}
|
||||
|
||||
func testSampleGame() {
|
||||
var bev = Beverage(withString: testData7)
|
||||
// printMaze(with: bev, withHP: true)
|
||||
while !bev.round() {}
|
||||
// printMaze(with: bev, withHP: true)
|
||||
var final = bev.tabulateScore()
|
||||
// print("Final score = \(final)")
|
||||
XCTAssertEqual(test: "testSampleGame 7", withExpression: (final == 27730))
|
||||
|
||||
bev = Beverage(withString: testData8)
|
||||
// printMaze(with: bev, withHP: true)
|
||||
while !bev.round() {}
|
||||
// printMaze(with: bev, withHP: true)
|
||||
final = bev.tabulateScore()
|
||||
// print("Final score = \(final)")
|
||||
XCTAssertEqual(test: "testSampleGame 8", withExpression: (final == 36334))
|
||||
|
||||
bev = Beverage(withString: testData9)
|
||||
// printMaze(with: bev, withHP: true)
|
||||
while !bev.round() {}
|
||||
// printMaze(with: bev, withHP: true)
|
||||
final = bev.tabulateScore()
|
||||
// print("Final score = \(final)")
|
||||
XCTAssertEqual(test: "testSampleGame 9", withExpression: (final == 39514))
|
||||
|
||||
bev = Beverage(withString: testData10)
|
||||
// printMaze(with: bev, withHP: true)
|
||||
while !bev.round() {}
|
||||
// printMaze(with: bev, withHP: true)
|
||||
final = bev.tabulateScore()
|
||||
// print("Final score = \(final)")
|
||||
XCTAssertEqual(test: "testSampleGame 10", withExpression: (final == 27755))
|
||||
|
||||
bev = Beverage(withString: testData11)
|
||||
// printMaze(with: bev, withHP: true)
|
||||
while !bev.round() {}
|
||||
// printMaze(with: bev, withHP: true)
|
||||
final = bev.tabulateScore()
|
||||
// print("Final score = \(final)")
|
||||
XCTAssertEqual(test: "testSampleGame 11", withExpression: (final == 28944))
|
||||
|
||||
bev = Beverage(withString: testData12)
|
||||
// printMaze(with: bev, withHP: true)
|
||||
while !bev.round() {}
|
||||
// printMaze(with: bev, withHP: true)
|
||||
final = bev.tabulateScore()
|
||||
// print("Final score = \(final)")
|
||||
XCTAssertEqual(test: "testSampleGame 12", withExpression: (final == 18740))
|
||||
|
||||
|
||||
// printMaze(with: bev, withHP: true)
|
||||
// bev.round()
|
||||
// printMaze(with: bev, withHP: true)
|
||||
// bev.round()
|
||||
// printMaze(with: bev, withHP: true)
|
||||
// for _ in 2..<23 {
|
||||
// bev.round()
|
||||
// }
|
||||
// printMaze(with: bev, withHP: true)
|
||||
// bev.round()
|
||||
// printMaze(with: bev, withHP: true)
|
||||
// bev.round()
|
||||
// printMaze(with: bev, withHP: true)
|
||||
// bev.round()
|
||||
// printMaze(with: bev, withHP: true)
|
||||
// bev.round()
|
||||
// printMaze(with: bev, withHP: true)
|
||||
// bev.round()
|
||||
// printMaze(with: bev, withHP: true)
|
||||
// for _ in 28..<46 {
|
||||
// bev.round()
|
||||
// }
|
||||
// printMaze(with: bev, withHP: true)
|
||||
// bev.round()
|
||||
// printMaze(with: bev, withHP: true)
|
||||
}
|
||||
|
||||
func printMaze(with bev: Beverage, withHP: Bool = false) {
|
||||
let width = bev.nummaze[0].count
|
||||
let height = bev.nummaze.count
|
||||
func toEntityHP(i: Int, j: Int) -> Int {
|
||||
var retVal = 0
|
||||
if let index = bev.entityDict[GridPoint(X: i, Y: j)] {
|
||||
retVal = bev.entities[index].hitPts
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
print(" ROUND \(bev.rounds)")
|
||||
for j in 0..<height {
|
||||
for i in 0..<width {
|
||||
switch bev.nummaze[j][i] {
|
||||
case .Wall: print(" # ", terminator: "")
|
||||
case .Unknown: print(" ? ", terminator: "")
|
||||
case .Open: print(" . ", terminator: "")
|
||||
case .Goblin: withHP ? print("\u{001B}[0;31m\(String(format: "%03d", toEntityHP(i:i, j:j)))\u{001B}[0;37m", terminator: "") : print(" G ", terminator: "")
|
||||
case .Elf: withHP ? print("\u{001B}[0;32m\(String(format: "%03d", toEntityHP(i:i, j:j)))\u{001B}[0;37m", terminator: "") : print(" E ", terminator: "")
|
||||
}
|
||||
}
|
||||
print("")
|
||||
}
|
||||
print("")
|
||||
}
|
||||
|
||||
|
||||
func day15Tests() {
|
||||
// testInitFile()
|
||||
// testInitString()
|
||||
// testEntities()
|
||||
// testDistance()
|
||||
// testMoveDirection()
|
||||
// testFindNearestTarget()
|
||||
// testAdjacent()
|
||||
// testTakeTurn()
|
||||
// testRound()
|
||||
// testAttack()
|
||||
// testSampleGame()
|
||||
}
|
||||
|
||||
func day15Final() {
|
||||
let retVal = "None"
|
||||
let bev = Beverage(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day15.txt")
|
||||
printMaze(with: bev, withHP: true)
|
||||
while !bev.round() {
|
||||
printMaze(with: bev, withHP: true)
|
||||
}
|
||||
// printMaze(with: bev, withHP: true)
|
||||
let final = bev.tabulateScore()
|
||||
|
||||
print("Answer to part 1 is: \(final)")
|
||||
print("Answer to part 2 is: \(retVal)")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,373 @@
|
||||
//
|
||||
// Advent of Code 2018 "Day 16: Chronal Classification"
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
typealias Opfn = () -> Void
|
||||
|
||||
// Create an array of functions for the op codes such that we can make a dictionary to map them
|
||||
// 16 op-codes
|
||||
// 4 regisers
|
||||
class Z8 {
|
||||
var reg: [Int]
|
||||
var op: Int
|
||||
var A: Int
|
||||
var B: Int
|
||||
var C: Int
|
||||
lazy var fn = [addr, addi, mulr, muli, banr, bani, borr, bori, setr, seti, gtir, gtri, gtrr, eqir, eqri, eqrr]
|
||||
|
||||
init(reg: [Int], op: Int, A: Int, B: Int, C: Int) {
|
||||
self.reg = reg
|
||||
self.op = op
|
||||
self.A = A
|
||||
self.B = B
|
||||
self.C = C
|
||||
}
|
||||
|
||||
// addr (add register) stores into register C the result of adding register A and register B. C = 7
|
||||
func addr() { reg[C] = reg[A] + reg[B] }
|
||||
// addi (add immediate) stores into register C the result of adding register A and value B.reg[C] = 5
|
||||
func addi() { reg[C] = reg[A] + B }
|
||||
// mulr (multiply register) stores into register C the result of multiplying register A and register B. reg[C] = 12
|
||||
func mulr() { reg[C] = reg[A] * reg[B] }
|
||||
// muli (multiply immediate) stores into register C the result of multiplying register A and value B. reg[C] = 6
|
||||
func muli() { reg[C] = reg[A] * B }
|
||||
// banr (bitwise AND register) stores into register C the result of the bitwise AND of register A and register B. reg[C] = 0
|
||||
func banr() { reg[C] = reg[A] & reg[B] }
|
||||
// bani (bitwise AND immediate) stores into register C the result of the bitwise AND of register A and value B. reg[C] = 2
|
||||
func bani() { reg[C] = reg[A] & B }
|
||||
// borr (bitwise OR register) stores into register C the result of the bitwise OR of register A and register B. reg[C] = 7
|
||||
func borr() { reg[C] = reg[A] | reg[B] }
|
||||
// bori (bitwise OR immediate) stores into register C the result of the bitwise OR of register A and value B. reg[C] = 3
|
||||
func bori() { reg[C] = reg[A] | B }
|
||||
// setr (set register) copies the contents of register A into register C. (Input B is ignored.) reg[C] = 3
|
||||
func setr() { reg[C] = reg[A] }
|
||||
// seti (set immediate) stores value A into register C. (Input B is ignored.) reg[C] = 1
|
||||
func seti() { reg[C] = A}
|
||||
// gtir (greater-than immediate/register) sets register C to 1 if value A is greater than register B. Otherwise, register C is set to 0. reg[C] = 0
|
||||
func gtir() { reg[C] = A > reg[B] ? 1 : 0 }
|
||||
// gtri (greater-than register/immediate) sets register C to 1 if register A is greater than value B. Otherwise, register C is set to 0. reg[C] = 1
|
||||
func gtri() { reg[C] = reg[A] > B ? 1 : 0 }
|
||||
// gtrr (greater-than register/register) sets register C to 1 if register A is greater than register B. Otherwise, register C is set to 0. reg[C] = 0
|
||||
func gtrr() { reg[C] = reg[A] > reg[B] ? 1 : 0 }
|
||||
// eqir (equal immediate/register) sets register C to 1 if value A is equal to register B. Otherwise, register C is set to 0. reg[C] = 0
|
||||
func eqir() { reg[C] = A == reg[B] ? 1 : 0 }
|
||||
// eqri (equal register/immediate) sets register C to 1 if register A is equal to value B. Otherwise, register C is set to 0. reg[C] = 0
|
||||
func eqri() { reg[C] = reg[A] == B ? 1 : 0 }
|
||||
// eqrr (equal register/register) sets register C to 1 if register A is equal to register B. Otherwise, register C is set to 0.reg[C] =0
|
||||
func eqrr() { reg[C] = reg[A] == reg[B] ? 1 : 0 }
|
||||
}
|
||||
|
||||
struct TestCase {
|
||||
var before: [Int]
|
||||
var after: [Int]
|
||||
var op: Int
|
||||
var A: Int
|
||||
var B: Int
|
||||
var C: Int
|
||||
|
||||
init(before: [Int], after: [Int], op: Int, A: Int, B: Int, C: Int) {
|
||||
self.before = before
|
||||
self.after = after
|
||||
self.op = op
|
||||
self.A = A
|
||||
self.B = B
|
||||
self.C = C
|
||||
}
|
||||
|
||||
func validate(withIndex fnIndex: Int) -> Bool {
|
||||
let z8 = Z8(reg: before, op: op, A: A, B: B, C: C)
|
||||
z8.fn[fnIndex]()
|
||||
return z8.reg == after
|
||||
}
|
||||
|
||||
func validate(withMapping map: [Int:Int]) -> Bool {
|
||||
let z8 = Z8(reg: before, op: op, A: A, B: B, C: C)
|
||||
z8.fn[map[op]!]()
|
||||
return z8.reg == after
|
||||
}
|
||||
|
||||
func countOpsValid() -> Int {
|
||||
let tempz8 = Z8(reg: before, op: op, A: A, B: B, C: C)
|
||||
var count = 0
|
||||
for opIndex in 0..<tempz8.fn.count {
|
||||
count += validate(withIndex: opIndex) ? 1 : 0
|
||||
}
|
||||
return count
|
||||
}
|
||||
}
|
||||
|
||||
struct Code {
|
||||
var op: Int
|
||||
var A: Int
|
||||
var B: Int
|
||||
var C: Int
|
||||
|
||||
init(op: Int, A: Int, B: Int, C: Int) {
|
||||
self.op = op
|
||||
self.A = A
|
||||
self.B = B
|
||||
self.C = C
|
||||
}
|
||||
}
|
||||
|
||||
class Classification {
|
||||
var tests: [TestCase] = []
|
||||
var program: [Code] = []
|
||||
|
||||
// Supply filename for input ex: '/home/peterr/AOC2018/Sources/AOC2018/data/day16.txt'
|
||||
init(withFile filename: String) {
|
||||
let testFile = Tools.readFile(fromPath: filename)
|
||||
var testStrings = testFile.components(separatedBy: "\n")
|
||||
// This gurd statement is just an excuse to use guard
|
||||
// I'm assuming the last string is an empty string, if not DON'T remove the last string
|
||||
guard let lastStr = testStrings.last, lastStr.count == 0 else { return }
|
||||
testStrings.removeLast() // empty string
|
||||
parse(data: testStrings)
|
||||
}
|
||||
|
||||
// Supply test data in the form of a String
|
||||
init(withString testFile: String) {
|
||||
let testStrings = testFile.components(separatedBy: "\n")
|
||||
parse(data: testStrings)
|
||||
}
|
||||
|
||||
func parse(data testStrings: [String]) {
|
||||
guard testStrings.count > 0 else { print("Error Parsing"); return }
|
||||
|
||||
func parseArray(with line: String) -> [Int] {
|
||||
var retVal: [Int] = []
|
||||
let split = line.components(separatedBy: "[")
|
||||
guard split.count == 2 else { print("Error Array 1"); return retVal }
|
||||
let split2 = split[1].components(separatedBy: "]")
|
||||
guard split2.count == 2 else { print("Error Array 2"); return retVal }
|
||||
let dataString = split2[0].replacingOccurrences(of: " ", with: "")
|
||||
let data = dataString.components(separatedBy: ",")
|
||||
retVal = data.map { Int($0)!}
|
||||
return retVal
|
||||
}
|
||||
|
||||
var testIntermediate = TestCase(before: [], after: [], op: 0, A: 0, B: 0, C: 0)
|
||||
for line in testStrings {
|
||||
if line.hasPrefix("Before") {
|
||||
testIntermediate.before = parseArray(with: line)
|
||||
} else if line.hasPrefix("After") {
|
||||
testIntermediate.after = parseArray(with: line)
|
||||
tests.append(testIntermediate)
|
||||
} else if line.count > 4 {
|
||||
let split = line.components(separatedBy: " ")
|
||||
guard split.count == 4 else { print("Error code \(line)"); return }
|
||||
testIntermediate.op = Int(split[0])!
|
||||
testIntermediate.A = Int(split[1])!
|
||||
testIntermediate.B = Int(split[2])!
|
||||
testIntermediate.C = Int(split[3])!
|
||||
} else {
|
||||
testIntermediate = TestCase(before: [], after: [], op: 0, A: 0, B: 0, C: 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Supply filename for input ex: '/home/peterr/AOC2018/Sources/AOC2018/data/day16Prog.txt'
|
||||
func loadProgram(withFile filename: String) {
|
||||
let progFile = Tools.readFile(fromPath: filename)
|
||||
var progStrings = progFile.components(separatedBy: "\n")
|
||||
// This gurd statement is just an excuse to use guard
|
||||
// I'm assuming the last string is an empty string, if not DON'T remove the last string
|
||||
guard let lastStr = progStrings.last, lastStr.count == 0 else { return }
|
||||
progStrings.removeLast() // empty string
|
||||
|
||||
var progIntermediate = Code(op: 0, A: 0, B: 0, C: 0)
|
||||
for line in progStrings {
|
||||
if line.count > 4 {
|
||||
let split = line.components(separatedBy: " ")
|
||||
guard split.count == 4 else { print("Error code 2 \(line)"); return }
|
||||
progIntermediate.op = Int(split[0])!
|
||||
progIntermediate.A = Int(split[1])!
|
||||
progIntermediate.B = Int(split[2])!
|
||||
progIntermediate.C = Int(split[3])!
|
||||
program.append(progIntermediate)
|
||||
progIntermediate = Code(op: 0, A: 0, B: 0, C: 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func runTests() -> Int {
|
||||
var validCount: [Int : Int] = [:]
|
||||
for testNum in 0..<tests.count {
|
||||
validCount[testNum] = tests[testNum].countOpsValid()
|
||||
}
|
||||
return validCount.filter {$0.value >= 3 }.count
|
||||
}
|
||||
|
||||
func validateMap(with map: [Int:Int]) -> Bool {
|
||||
for test in tests {
|
||||
if !test.validate(withMapping: map) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// returns the content of register zero
|
||||
func runProgram(with map: [Int:Int]) -> Int {
|
||||
let z8 = Z8(reg: [0, 0, 0, 0], op: 0, A: 0, B: 0, C: 0)
|
||||
|
||||
for lineIndex in 0..<program.count {
|
||||
z8.A = program[lineIndex].A
|
||||
z8.B = program[lineIndex].B
|
||||
z8.C = program[lineIndex].C
|
||||
z8.fn[map[program[lineIndex].op]!]()
|
||||
}
|
||||
return z8.reg[0]
|
||||
}
|
||||
|
||||
// Return a map of [SysOp : myOp]
|
||||
func determineOps() -> [Int:Int] {
|
||||
var possibleOpCodes: [Int : [Int]] = [:]
|
||||
for myOpCode in 0..<16 {
|
||||
var sysOp: [Int: Bool] = [:]
|
||||
for test in tests {
|
||||
if test.validate(withIndex: myOpCode) {
|
||||
sysOp[test.op] = true
|
||||
}
|
||||
}
|
||||
possibleOpCodes[myOpCode] = Array(sysOp.keys)
|
||||
}
|
||||
// We have 16 sets off opcodes, now reduce them
|
||||
func doneTest() -> Bool {
|
||||
for possible in possibleOpCodes {
|
||||
if possible.value.count > 1 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
while !doneTest() {
|
||||
for index in 0..<possibleOpCodes.count {
|
||||
if possibleOpCodes[index]!.count == 1 {
|
||||
for inner in 0..<possibleOpCodes.count {
|
||||
if inner != index {
|
||||
var possibleArray = possibleOpCodes[inner]!
|
||||
possibleArray.removeAll(where: { $0 == possibleOpCodes[index]![0] })
|
||||
possibleOpCodes[inner] = possibleArray
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var retVal: [Int:Int] = [:]
|
||||
for myOpCode in 0..<16 {
|
||||
let sysOp = possibleOpCodes[myOpCode]![0]
|
||||
retVal[sysOp] = myOpCode
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Day16: AOCDay {
|
||||
lazy var tests: (() -> ()) = day16Tests
|
||||
lazy var final: (() -> ()) = day16Final
|
||||
|
||||
let testData1 = """
|
||||
Before: [3, 2, 1, 1]
|
||||
9 2 1 2
|
||||
After: [3, 2, 2, 1]
|
||||
|
||||
"""
|
||||
|
||||
func testZ8Instructions() {
|
||||
let z8 = Z8(reg: [0, 0, 0, 0], op: 0, A: 0, B: 0, C: 0)
|
||||
func initZ8() { z8.A = 1; z8.B = 2; z8.reg = [1, 3, 4, 2] }
|
||||
initZ8(); z8.addr()
|
||||
XCTAssertEqual(test: "testZ8Instructions addr", withExpression: (z8.reg[z8.C] == 7))
|
||||
initZ8(); z8.addi()
|
||||
XCTAssertEqual(test: "testZ8Instructions addi", withExpression: (z8.reg[z8.C] == 5))
|
||||
initZ8(); z8.mulr()
|
||||
XCTAssertEqual(test: "testZ8Instructions mulr", withExpression: (z8.reg[z8.C] == 12))
|
||||
initZ8(); z8.muli()
|
||||
XCTAssertEqual(test: "testZ8Instructions muli", withExpression: (z8.reg[z8.C] == 6))
|
||||
initZ8(); z8.banr()
|
||||
XCTAssertEqual(test: "testZ8Instructions banr", withExpression: (z8.reg[z8.C] == 0))
|
||||
initZ8(); z8.bani()
|
||||
XCTAssertEqual(test: "testZ8Instructions bani", withExpression: (z8.reg[z8.C] == 2))
|
||||
initZ8(); z8.borr()
|
||||
XCTAssertEqual(test: "testZ8Instructions borr", withExpression: (z8.reg[z8.C] == 7))
|
||||
initZ8(); z8.bori()
|
||||
XCTAssertEqual(test: "testZ8Instructions bori", withExpression: (z8.reg[z8.C] == 3))
|
||||
initZ8(); z8.setr()
|
||||
XCTAssertEqual(test: "testZ8Instructions setr", withExpression: (z8.reg[z8.C] == 3))
|
||||
initZ8(); z8.seti()
|
||||
XCTAssertEqual(test: "testZ8Instructions seti", withExpression: (z8.reg[z8.C] == 1))
|
||||
initZ8(); z8.gtir()
|
||||
XCTAssertEqual(test: "testZ8Instructions gtir", withExpression: (z8.reg[z8.C] == 0))
|
||||
initZ8(); z8.gtri()
|
||||
XCTAssertEqual(test: "testZ8Instructions gtri", withExpression: (z8.reg[z8.C] == 1))
|
||||
initZ8(); z8.gtrr()
|
||||
XCTAssertEqual(test: "testZ8Instructions gtrr", withExpression: (z8.reg[z8.C] == 0))
|
||||
initZ8(); z8.eqir()
|
||||
XCTAssertEqual(test: "testZ8Instructions eqir", withExpression: (z8.reg[z8.C] == 0))
|
||||
initZ8(); z8.eqri()
|
||||
XCTAssertEqual(test: "testZ8Instructions eqri", withExpression: (z8.reg[z8.C] == 0))
|
||||
initZ8(); z8.eqrr()
|
||||
XCTAssertEqual(test: "testZ8Instructions eqrr", withExpression: (z8.reg[z8.C] == 0))
|
||||
}
|
||||
|
||||
func testInitFile() {
|
||||
let cla = Classification(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day16.txt")
|
||||
XCTAssertEqual(test: "testInitFile count", withExpression: (cla.tests.count > 0))
|
||||
XCTAssertEqual(test: "testInitFile before", withExpression: (cla.tests.last!.before == [3, 1, 2, 2]))
|
||||
XCTAssertEqual(test: "testInitFile after", withExpression: (cla.tests.last!.after == [3, 1, 2, 0]))
|
||||
XCTAssertEqual(test: "testInitFile op", withExpression: (cla.tests.last!.op == 11))
|
||||
XCTAssertEqual(test: "testInitFile A", withExpression: (cla.tests.last!.A == 1))
|
||||
XCTAssertEqual(test: "testInitFile B", withExpression: (cla.tests.last!.B == 2))
|
||||
XCTAssertEqual(test: "testInitFile C", withExpression: (cla.tests.last!.C == 3))
|
||||
}
|
||||
|
||||
func testInitString() {
|
||||
let cla = Classification(withString: testData1)
|
||||
XCTAssertEqual(test: "testInitString count", withExpression: (cla.tests.count > 0))
|
||||
XCTAssertEqual(test: "testInitString before", withExpression: (cla.tests[0].before == [3, 2, 1, 1]))
|
||||
XCTAssertEqual(test: "testInitString after", withExpression: (cla.tests[0].after == [3, 2, 2, 1]))
|
||||
XCTAssertEqual(test: "testInitString op", withExpression: (cla.tests[0].op == 9))
|
||||
XCTAssertEqual(test: "testInitString A", withExpression: (cla.tests[0].A == 2))
|
||||
XCTAssertEqual(test: "testInitString B", withExpression: (cla.tests[0].B == 1))
|
||||
XCTAssertEqual(test: "testInitString C", withExpression: (cla.tests[0].C == 2))
|
||||
}
|
||||
|
||||
func testCountValidOps3orMore() {
|
||||
let cla = Classification(withString: testData1)
|
||||
let testCount = cla.runTests()
|
||||
XCTAssertEqual(test: "testCountValidOps3orMore count", withExpression: (testCount == 1))
|
||||
}
|
||||
|
||||
func testValidateWithMapping() {
|
||||
let cla = Classification(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day16.txt")
|
||||
let mapping = cla.determineOps()
|
||||
let works = cla.validateMap(with: mapping)
|
||||
XCTAssertEqual(test: "testValidateWithMapping", withExpression: (works == true))
|
||||
}
|
||||
|
||||
func day16Tests() {
|
||||
testZ8Instructions()
|
||||
testInitFile()
|
||||
testInitString()
|
||||
testCountValidOps3orMore()
|
||||
testValidateWithMapping()
|
||||
}
|
||||
|
||||
func day16Final() {
|
||||
let cla = Classification(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day16.txt")
|
||||
let testCount = cla.runTests()
|
||||
|
||||
print("Answer to part 1 is: \(testCount)")
|
||||
|
||||
let mapping = cla.determineOps()
|
||||
cla.loadProgram(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day16Prog.txt")
|
||||
let reg0 = cla.runProgram(with: mapping)
|
||||
|
||||
print("Answer to part 2 is: \(reg0)")
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
import Foundation
|
||||
|
||||
let showTests = true
|
||||
let onlyOneDay = 0
|
||||
let onlyOneDay = 16
|
||||
var allTests: [(() -> ())] = []
|
||||
var allFinal: [(() -> ())] = []
|
||||
|
||||
@@ -13,9 +13,39 @@ print("Advent of Code 2018")
|
||||
|
||||
// Compile list of Tests
|
||||
allTests.append(Day01().tests)
|
||||
allTests.append(Day02().tests)
|
||||
allTests.append(Day03().tests)
|
||||
allTests.append(Day04().tests)
|
||||
allTests.append(Day05().tests)
|
||||
allTests.append(Day06().tests)
|
||||
allTests.append(Day07().tests)
|
||||
allTests.append(Day08().tests)
|
||||
allTests.append(Day09().tests)
|
||||
allTests.append(Day10().tests)
|
||||
allTests.append(Day11().tests)
|
||||
allTests.append(Day12().tests)
|
||||
allTests.append(Day13().tests)
|
||||
allTests.append(Day14().tests)
|
||||
allTests.append(Day15().tests)
|
||||
allTests.append(Day16().tests)
|
||||
|
||||
// Compile list of Answers
|
||||
allFinal.append(Day01().final)
|
||||
allFinal.append(Day02().final)
|
||||
allFinal.append(Day03().final)
|
||||
allFinal.append(Day04().final)
|
||||
allFinal.append(Day05().final)
|
||||
allFinal.append(Day06().final)
|
||||
allFinal.append(Day07().final)
|
||||
allFinal.append(Day08().final)
|
||||
allFinal.append(Day09().final)
|
||||
allFinal.append(Day10().final)
|
||||
allFinal.append(Day11().final)
|
||||
allFinal.append(Day12().final)
|
||||
allFinal.append(Day13().final)
|
||||
allFinal.append(Day14().final)
|
||||
allFinal.append(Day15().final)
|
||||
allFinal.append(Day16().final)
|
||||
|
||||
if onlyOneDay > 0 {
|
||||
print("\nDay \(onlyOneDay)")
|
||||
|
||||
@@ -14,6 +14,45 @@ func XCTAssertEqual(test: String, withExpression isTrue: Bool) {
|
||||
print(test)
|
||||
}
|
||||
|
||||
func == <T:Equatable> (tuple1:(T,T),tuple2:(T,T)) -> Bool
|
||||
{
|
||||
return (tuple1.0 == tuple2.0) && (tuple1.1 == tuple2.1)
|
||||
}
|
||||
|
||||
struct GridDir {
|
||||
static let none = GridPoint(X: 0, Y: 0)
|
||||
static let up = GridPoint(X: 0, Y: -1)
|
||||
static let down = GridPoint(X: 0, Y: 1)
|
||||
static let left = GridPoint(X: -1, Y: 0)
|
||||
static let right = GridPoint(X: 1, Y: 0)
|
||||
}
|
||||
|
||||
struct GridPoint: Equatable, Comparable, Hashable {
|
||||
var X = 0
|
||||
var Y = 0
|
||||
var up: GridPoint { return GridPoint(X: self.X, Y: self.Y-1) }
|
||||
var down: GridPoint { return GridPoint(X: self.X, Y: self.Y+1) }
|
||||
var left: GridPoint { return GridPoint(X: self.X-1, Y: self.Y) }
|
||||
var right: GridPoint {return GridPoint(X: self.X+1, Y: self.Y) }
|
||||
|
||||
var hashValue: Int { return X.hashValue ^ Y.hashValue }
|
||||
|
||||
static func == (lhs: GridPoint, rhs: GridPoint) -> Bool {
|
||||
return (lhs.X == rhs.X) && (lhs.Y == rhs.Y)
|
||||
}
|
||||
|
||||
static func < (lhs: GridPoint, rhs: GridPoint) -> Bool {
|
||||
return lhs.Y == rhs.Y ? lhs.X < rhs.X : lhs.Y < rhs.Y
|
||||
}
|
||||
|
||||
static func + (lhs: GridPoint, rhs: GridPoint) -> GridPoint {
|
||||
return GridPoint(X: lhs.X + rhs.X, Y: lhs.Y + rhs.Y)
|
||||
}
|
||||
|
||||
static func - (lhs: GridPoint, rhs: GridPoint) -> GridPoint {
|
||||
return GridPoint(X: lhs.X - rhs.X, Y: lhs.Y - rhs.Y)
|
||||
}
|
||||
}
|
||||
|
||||
struct Tools {
|
||||
static func readFile(fromPath path: String) -> String {
|
||||
@@ -27,4 +66,61 @@ struct Tools {
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
// Assumes THE string is 'polymer'
|
||||
static func stringIndexRange(withString str: String, fromRange range: Range<Int>) -> Range<String.Index> {
|
||||
let myrange = Range(uncheckedBounds: (lower: max(0, min(str.length, range.lowerBound)), upper: min(str.length, max(0, range.upperBound))))
|
||||
let start = str.index(str.startIndex, offsetBy: myrange.lowerBound)
|
||||
let end = str.index(start, offsetBy: myrange.upperBound - myrange.lowerBound)
|
||||
return start ..< end
|
||||
}
|
||||
}
|
||||
|
||||
extension Character {
|
||||
var isAscii: Bool {
|
||||
return unicodeScalars.first?.isASCII == true
|
||||
}
|
||||
var ascii: UInt32? {
|
||||
return isAscii ? unicodeScalars.first?.value : nil
|
||||
}
|
||||
}
|
||||
|
||||
extension StringProtocol {
|
||||
// var string: String { return String(self) }
|
||||
|
||||
var ascii: [UInt32] {
|
||||
return compactMap { $0.ascii }
|
||||
}
|
||||
|
||||
subscript(offset: Int) -> Element {
|
||||
return self[index(startIndex, offsetBy: offset)]
|
||||
}
|
||||
}
|
||||
|
||||
extension String {
|
||||
|
||||
var length: Int {
|
||||
return count
|
||||
}
|
||||
|
||||
subscript (i: Int) -> String {
|
||||
return self[i ..< i + 1]
|
||||
}
|
||||
|
||||
func substring(fromIndex: Int) -> String {
|
||||
return self[min(fromIndex, length) ..< length]
|
||||
}
|
||||
|
||||
func substring(toIndex: Int) -> String {
|
||||
return self[0 ..< max(0, toIndex)]
|
||||
}
|
||||
|
||||
subscript (r: Range<Int>) -> String {
|
||||
let range = Range(uncheckedBounds: (lower: max(0, min(length, r.lowerBound)),
|
||||
upper: min(length, max(0, r.upperBound))))
|
||||
let start = index(startIndex, offsetBy: range.lowerBound)
|
||||
let end = index(start, offsetBy: range.upperBound - range.lowerBound)
|
||||
return String(self[start ..< end])
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user