···11+import fileinput
22+from utils import Point
33+44+55+def sign(x, y):
66+ if x > y:
77+ return 1
88+ elif x < y:
99+ return -1
1010+ else:
1111+ return 0
1212+1313+1414+def update(head, tail):
1515+ """
1616+ Given the current position of head and tail,
1717+ return the new tail position.
1818+ """
1919+2020+ # This occurs if we have moved diagonally away from the tail,
2121+ # and it is far enough for the tail to come and chase us.
2222+ if abs(head.x - tail.x) + abs(head.y - tail.y) > 2:
2323+ tail += Point(sign(head.x, tail.x), sign(head.y, tail.y))
2424+2525+ # Check if we need to move horizontally/vertically.
2626+ elif (head.x == tail.x or head.y == tail.y) and (abs(head.x - tail.x) + abs(head.y - tail.y) > 1):
2727+ tail += Point(sign(head.x, tail.x), sign(head.y, tail.y))
2828+2929+ return tail
3030+3131+3232+mapping = {
3333+ "U": Point(0, 1),
3434+ "R": Point(1, 0),
3535+ "D": Point(0, -1),
3636+ "L": Point(-1, 0),
3737+}
3838+3939+INSTRUCTIONS = [line.strip() for line in fileinput.input()]
4040+4141+# Solve problem.
4242+for part, bridge_len in ((1, 2), (2, 10)):
4343+ bridge = [Point(0, 0) for _ in range(bridge_len)]
4444+ seen = set()
4545+4646+ for line in INSTRUCTIONS:
4747+ d, amt = line.split()
4848+ amt = int(amt)
4949+5050+ for _ in range(amt):
5151+ # First, move the head in the given direction.
5252+ bridge[0] += mapping[d]
5353+ for i in range(1, bridge_len):
5454+ bridge[i] = update(bridge[i-1], bridge[i])
5555+ seen.add(bridge[-1])
5656+5757+ print(f"Part {part}: {len(seen)}")
5858+