-
Notifications
You must be signed in to change notification settings - Fork 0
/
day13.nim
72 lines (59 loc) · 1.98 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
import algorithm
import bitops
import re
import sequtils
import strutils
import sugar
# Parse input
let inputFileName = "resources/day13_input.txt"
let inputFile = open(inputFileName)
# First line is always time of arrival
let timeOfArrival = parseInt(inputFile.readLine())
# Extract IDs from second line using regex
let rawIds = inputFile.readLine()
let pattern = re"\d+"
let busIds = rawIds.findAll(pattern).map(parseInt)
# Calculate text bus times
let nextBus = busIds.map(x => x - timeOfArrival mod x)
# Find earliest departure
let earliestBusIndex = nextBus.minIndex
let earliestBusId = busIds[earliestBusIndex]
let earliestBusTime = nextBus[earliestBusIndex]
# Print results
echo "--- Part 1 Report ---"
echo "ID * Waiting time = " & $(earliestBusId * earliestBusTime)
## Part 2
# Modular exponentiation
proc modpow(base, exp, modulus: uint64): uint64 =
result = 1;
var exp = exp
var base = base mod modulus
while (exp > 0):
if exp.testBit(0):
result = (result * base) mod modulus
base = (base * base) mod modulus
exp = exp shr 1
# Modular division
proc moddiv(a, b, modulus: uint64): uint64 =
let a = a mod modulus
let inv = modpow(b, modulus - 2, modulus)
result = (inv * a) mod modulus
# Parse input
var unsortedBusTable: seq[(uint64, uint64)]
for idx, val in @(rawIds.split(',')):
if val[0] != 'x':
let id = parseInt(val)
unsortedBusTable.add((uint64(id), uint64(idx mod id)))
let busTable = unsortedBusTable.sorted((x, y) => system.cmp[uint64](x[1], y[1]))
# Find timestamp making use of the fact that every bus ID is a prime number
var compPeriod: uint64 = 1
var time: uint64 = 0
# time + compPeriod * t mod period = period - phase mod period
# (period - phase - sum) / compPeriod mod period = t
for (period, phase) in busTable:
let t = moddiv(period - (phase + time mod period), compPeriod, period)
time += t * compPeriod
compPeriod *= period # Gets LCM as all the IDs are coprimes
# Print results
echo "--- Part 2 Report ---"
echo "Timestamp = " & $time