-
Notifications
You must be signed in to change notification settings - Fork 3
/
day13.nim
97 lines (73 loc) · 2.44 KB
/
day13.nim
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import strutils, intsets, tables, sequtils, math
proc makeFirewall(f: string): Table[int, IntSet] =
let instructions = readFile(f).splitLines()
for line in instructions:
let
numbers = line.split(": ").map(parseInt)
depth = numbers[0]
height = numbers[1]
if not result.hasKey(height):
result[height] = initIntSet()
result[height].incl(depth)
let firewall = makeFirewall("./inputs/13.txt")
func isCaught(depth, height: int, delay = 0): bool =
(depth + delay) mod (2 * (height - 1)) == 0
func calculateSeverity(firewall: Table[int, IntSet]): int =
for height in firewall.keys:
for depth in firewall[height]:
if isCaught(depth, height):
result += depth * height
func oneRemains(height: int, depths: IntSet): bool =
depths.card == height - 2
type
Group = tuple[height: int, depths: IntSet]
Groups = seq[Group]
var
calcGroup: Groups = @[]
controlGroup: Groups = @[]
for h in firewall.keys:
if oneRemains(h, firewall[h]):
calcGroup.add((h, firewall[h]))
else:
controlGroup.add((h, firewall[h]))
func pymod(a, b: int): int =
let m = -a mod b
if m == 0: 0 else: m+b
func findAllowedDelay(height: int, depths: IntSet): tuple[delay, period: int] =
let period = 2 * (height - 1)
var
potential = initIntSet()
forbidden = initIntSet()
for i in countup(0, period-1, 2): potential.incl(i)
for depth in depths: forbidden.incl(pymod(depth, period))
var allowed = potential - forbidden
var e: int # poor man's pop
for i in allowed: e = i; break
result = (e, period)
func findDelayParams(walls: Groups): tuple[delay, step: int] =
var
delays: seq[int] = @[]
periods: seq[int] = @[]
for hd in walls:
let (delay, period) = findAllowedDelay(hd.height, hd.depths)
delays.add(delay)
periods.add(period)
let commonMulti = periods.foldl(lcm(a, b))
var allowedDelays = initIntSet()
for i in 0 ..< commonMulti: allowedDelays.incl(i)
for (d, p) in zip(delays, periods):
var s = initIntSet()
for i in countup(0, commonMulti-1, p): s.incl(d + i)
allowedDelays = allowedDelays * s
var e: int # poor man's pop
for i in allowedDelays: e = i; break
result = (e, commonMulti)
func isCaught(hd: Group, delay: int): bool =
for d in hd.depths:
if isCaught(d, hd.height, delay):
return true
var (delay, step) = calcGroup.findDelayParams()
while controlGroup.anyIt(it.isCaught(delay)):
delay += step
echo firewall.calculateSeverity()
echo delay