-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsolution.nim
131 lines (107 loc) · 2.7 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
import ../../lib/imports
type
Cups = ref object
head: int
next: Table[int, int]
proc parse(input: string): Cups =
result.new
let a = input.toSeq.mapIt(it.ord - '0'.ord)
for i in 0 ..< a.len:
result.next[a[i]] = a[(i + 1) mod a.len]
result.head = a[0]
when defined(test):
let input = """
389125467
""".strip
block:
let cups = input.parse
doAssert cups.head == 3
doAssert cups.next == { 3: 8, 8: 9, 9: 1, 1: 2, 2: 5, 5: 4, 4: 6, 6: 7, 7: 3 }.toTable
proc step(cups: Cups) =
let N = cups.next.len
proc minus1(x: int): int =
(x - 1 - 1 + N) mod N + 1
let pickupFirst = cups.next[cups.head]
var pickupLast = cups.head
var pickups = newSeq[int]()
for _ in 0 ..< 3:
pickupLast = cups.next[pickupLast]
pickups.add pickupLast
cups.next[cups.head] = cups.next[pickupLast]
var dst = cups.head.minus1
while dst in pickups:
dst = dst.minus1
block:
let t = cups.next[dst]
cups.next[dst] = pickupFirst
cups.next[pickupLast] = t
cups.head = cups.next[cups.head]
proc toSeq(cups: Cups): seq[int] =
var p = cups.head
result.add p
p = cups.next[p]
while p != cups.head:
result.add p
p = cups.next[p]
when defined(test):
block:
var cups = input.parse
for e in @[
@[2, 8, 9, 1, 5, 4, 6, 7, 3],
@[5, 4, 6, 7, 8, 9, 1, 3, 2],
@[8, 9, 1, 3, 4, 6, 7, 2, 5],
@[4, 6, 7, 9, 1, 3, 2, 5, 8],
@[1, 3, 6, 7, 9, 2, 5, 8, 4],
@[9, 3, 6, 7, 2, 5, 8, 4, 1],
@[2, 5, 8, 3, 6, 7, 4, 1, 9],
@[6, 7, 4, 1, 5, 8, 3, 9, 2],
@[5, 7, 4, 1, 8, 3, 9, 2, 6]
]:
cups.step
doAssert cups.toSeq == e
proc `$`(cups: Cups): string =
var p = cups.next[1]
while p != 1:
result &= ('0'.ord + p).char
p = cups.next[p]
proc move(cups: Cups, repeat: int) =
for _ in 0 ..< repeat:
cups.step
when defined(test):
block:
let cups = input.parse
cups.move(10)
doAssert $cups == "92658374"
block:
let cups = input.parse
cups.move(100)
doAssert $cups == "67384529"
proc part1(input: string): string =
let cups = input.parse
cups.move(100)
$cups
proc parse2(input: string): Cups =
result.new
let a = input.toSeq.mapIt(it.ord - '0'.ord)
for i in 0 ..< a.len - 1:
result.next[a[i]] = a[i + 1]
var p = a.len + 1
result.next[a[^1]] = p
while p < 1e6.int:
result.next[p] = p + 1
p += 1
result.next[p] = a[0]
result.head = a[0]
proc part2(input: string): int =
let cups = input.parse2
cups.move(1e7.int)
let p = cups.next[1]
let q = cups.next[p]
p * q
when defined(test):
block:
doAssert part2(input) == 149245887792
when isMainModule and not defined(test):
let input = readFile("input").strip
echo part1(input)
echo part2(input)