lines = [] with open("13.input") as f: for line in f.readlines(): lines.append(line.strip()) busses = [int(x) for x in lines[1].split(",") if x != "x"] my_time = int(lines[0]) times = [x - my_time % x for x in busses] my_bus = busses[times.index(min(times))] print("Answer 1: {}".format(my_bus * min(times))) busses = [(- i % int(x), int(x)) for (i, x) in enumerate(lines[1].split(",")) if x != "x"] def print_table(start, busses): end = start + busses[-1][0] for i in range(start, end): print("{}: ".format(i), end='') for (offset, interval) in busses: if i % interval == 0: print('D', end='') else: print('.', end='') print("") # Stolen from: https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm#Pseudocode def extended_gcd(a, b): (old_r, r) = (a, b) (old_s, s) = (1, 0) (old_t, t) = (0, 1) while r != 0: quotient = int(old_r / r) (old_r, r) = (r, old_r - quotient * r) (old_s, s) = (s, old_s - quotient * s) (old_t, t) = (t, old_t - quotient * t) return (old_s, old_t) def combo(pair1, pair2): off1, int1 = pair1 off2, int2 = pair2 # This is fine since all IDs are primes new_int = int1 * int2 # Find the smallest solution to # int1 * x + off1 = int2 * y + off2 # int1 * x - int2 * y = 1 * (off2 - off1) x, y = extended_gcd(int1, -int2) # Correct signs if int1 * x - int2 * y != 1: x = -x y = -y x *= (off2 - off1) y *= (off2 - off1) assert int1 * x + off1 == int2 * y + off2 return ((int1 * x + off1) % new_int, new_int) result_busses = list(busses) while len(result_busses) > 1: result_busses = [combo(result_busses[0], result_busses[1])] + result_busses[2:] print("Answer 2: {}".format(result_busses[0][0]))