-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsolution.nim
133 lines (110 loc) · 3.06 KB
/
solution.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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import std/[
algorithm,
bitops,
deques,
json,
math,
re,
sequtils,
sets,
strformat,
strutils,
tables,
sugar,
]
type
Equipments = (int, int)
proc parseLine(line: string): Equipments =
var chips, generators = 0
for m in line.findAll(re"\b\w+(\-compatible microchip| generator)"):
if m =~ re"(\w+)-compatible microchip":
chips += 1
elif m =~ re"(\w+) generator":
generators += 1
(chips, generators)
when defined(test):
let input = """
The first floor contains a hydrogen-compatible microchip and a lithium-compatible microchip.
The second floor contains a hydrogen generator.
The third floor contains a lithium generator.
The fourth floor contains nothing relevant.
""".strip
block:
let lines = input.split("\n")
doAssert parseLine(lines[0]) == (2, 0)
doAssert parseLine(lines[1]) == (0, 1)
doAssert parseLine(lines[2]) == (0, 1)
doAssert parseLine(lines[3]) == (0, 0)
type
Facility = object
elevator: int
floors: array[4, Equipments]
proc parse(input: string): Facility =
var floors: array[4, Equipments]
for i, line in input.split("\n").toSeq:
floors[i] = parseLine(line)
Facility(floors: floors)
when defined(test):
block:
let f = parse(input)
doAssert f.elevator == 0
doAssert f.floors == [(2, 0), (0, 1), (0, 1), (0, 0)]
proc finished(self: Facility): bool =
for i in 0 .. 2:
if self.floors[i] != (0, 0): return false
true
proc isValid(floor: Equipments): bool =
let (cs, gs) = floor
if cs < 0 or gs < 0: return false
gs == 0 or cs <= gs
proc `+`(a, b: Equipments): Equipments =
(a[0] + b[0], a[1] + b[1])
proc `-`(a, b: Equipments): Equipments =
(a[0] - b[0], a[1] - b[1])
proc move(self: Facility, equipments: Equipments, target: int): (bool, Facility) =
let fromFloor = self.floors[self.elevator] - equipments
if not fromFloor.isValid: return (false, self)
let toFloor = self.floors[target] + equipments
if not toFloor.isValid: return (false, self)
var floors = self.floors
floors[self.elevator] = fromFloor
floors[target] = toFloor
(true, Facility(elevator: target, floors: floors))
iterator next(self: Facility): Facility =
for target in 0 .. 3:
if (self.elevator - target).abs != 1: continue
for i in 0 .. 2:
for j in 0 .. 2:
if i + j in 1 .. 2:
let (ok, nf) = self.move((i, j), target)
if ok: yield nf
proc bfs(f: Facility): int =
var q = @[f]
var visited = initHashSet[Facility]()
visited.incl f
var steps = 0
while q.len > 0:
var next: typeof q = @[]
for f in q:
if f.finished: return steps
for nf in f.next:
if nf in visited: continue
visited.incl nf
next.add nf
q = next
steps += 1
proc part1(input: string): int =
let f = parse(input)
bfs(f)
when defined(test):
block:
doAssert part1(input) == 11
proc part2(input: string): int =
var f = parse(input)
let (cs, gs) = f.floors[0]
f.floors[0] = (cs + 2, gs + 2)
bfs(f)
when isMainModule and not defined(test):
let input = readAll(stdin).strip
echo part1(input)
echo part2(input)