allow_reflections = True
ANGLE_COMPLEMENTS = {"A": "C", "F": "F", "C": "A"}
MOVE_ENUMS = {"U": 0, "R": 1, "D": 2, "L": 3}
FOUND_ANGLE_STRS = set()
def convert(x,y):
if x == y:
return "F"
elif (MOVE_ENUMS[x] - MOVE_ENUMS[y]) % 4 == 1:
return "C"
else:
return "A"
def to_angles(moves):
angles = []
for i in range(1, len(moves)):
angles.append(convert(moves[i], moves[i-1]))
angles.append(convert(moves[0], moves[len(moves)-1]))
return "".join(angles)
def equal(angle_str1, angle_str2):
n = len(angle_str1)
# Check if cyclically equal
for i in range(n):
rotated_as1 = angle_str1[i:] + angle_str1[:i]
if rotated_as1 == angle_str2 or (not allow_reflections and rotated_as1[::-1] == angle_str2):
return True
# Convert A <-> C and check if cyclically equal
converted_as1 = "".join(ANGLE_COMPLEMENTS[c] for c in angle_str1)
for i in range(n):
rotated_cas1 = converted_as1[i:] + converted_as1[:i]
if rotated_cas1 == angle_str2 or (not allow_reflections and rotated_cas1[::-1] == angle_str2):
return True
return False
def solve(rods, point=(0, 0), moves="", moves2="", visited=None):
if not rods:
angle_str = to_angles(moves2)
if point == (0, 0) and angle_str.count("A") - angle_str.count("C") == 4:
for f in FOUND_ANGLE_STRS:
if equal(f, angle_str):
break
else:
FOUND_ANGLE_STRS.add(angle_str)
print(moves, angle_str)
return
if not visited:
visited = set()
r = rods.pop(0)
for move, direction in [((r,0), "R"), ((0,r), "U"), ((-r,0), "L"), ((0,-r), "D")]:
new_point = (move[0] + point[0], move[1] + point[1])
added_visited = set()
search = True
for i in range(min(point[0],new_point[0]), max(point[0],new_point[0])+1):
for j in range(min(point[1],new_point[1]), max(point[1],new_point[1])+1):
if (i, j) != point:
if (i, j) in visited:
search = False
for a in added_visited:
visited.remove(a)
added_visited = set()
break
else:
visited.add((i, j))
added_visited.add((i, j))
if not search:
break
if search:
solve(rods, new_point, moves + direction, moves2 + direction*r, visited)
for a in added_visited:
visited.remove(a)
rods.insert(0, r)
solve([1]*10)
YWxsb3dfcmVmbGVjdGlvbnMgPSBUcnVlCgpBTkdMRV9DT01QTEVNRU5UUyA9IHsiQSI6ICJDIiwgIkYiOiAiRiIsICJDIjogIkEifQpNT1ZFX0VOVU1TID0geyJVIjogMCwgIlIiOiAxLCAiRCI6IDIsICJMIjogM30KRk9VTkRfQU5HTEVfU1RSUyA9IHNldCgpCgpkZWYgY29udmVydCh4LHkpOgogICAgaWYgeCA9PSB5OgogICAgICAgIHJldHVybiAiRiIKICAgIGVsaWYgKE1PVkVfRU5VTVNbeF0gLSBNT1ZFX0VOVU1TW3ldKSAlIDQgPT0gMToKICAgICAgICByZXR1cm4gIkMiCiAgICBlbHNlOgogICAgICAgIHJldHVybiAiQSIKICAgICAgICAKZGVmIHRvX2FuZ2xlcyhtb3Zlcyk6CiAgICBhbmdsZXMgPSBbXQoKICAgIGZvciBpIGluIHJhbmdlKDEsIGxlbihtb3ZlcykpOgogICAgICAgIGFuZ2xlcy5hcHBlbmQoY29udmVydChtb3Zlc1tpXSwgbW92ZXNbaS0xXSkpCgogICAgYW5nbGVzLmFwcGVuZChjb252ZXJ0KG1vdmVzWzBdLCBtb3Zlc1tsZW4obW92ZXMpLTFdKSkKCiAgICByZXR1cm4gIiIuam9pbihhbmdsZXMpCiAgICAKCmRlZiBlcXVhbChhbmdsZV9zdHIxLCBhbmdsZV9zdHIyKToKICAgIG4gPSBsZW4oYW5nbGVfc3RyMSkKCiAgICAjIENoZWNrIGlmIGN5Y2xpY2FsbHkgZXF1YWwKICAgIGZvciBpIGluIHJhbmdlKG4pOgogICAgICAgIHJvdGF0ZWRfYXMxID0gYW5nbGVfc3RyMVtpOl0gKyBhbmdsZV9zdHIxWzppXQogICAgICAgIAogICAgICAgIGlmIHJvdGF0ZWRfYXMxID09IGFuZ2xlX3N0cjIgb3IgKG5vdCBhbGxvd19yZWZsZWN0aW9ucyBhbmQgcm90YXRlZF9hczFbOjotMV0gPT0gYW5nbGVfc3RyMik6CiAgICAgICAgICAgICAgICByZXR1cm4gVHJ1ZQoKICAgICMgQ29udmVydCBBIDwtPiBDIGFuZCBjaGVjayBpZiBjeWNsaWNhbGx5IGVxdWFsCiAgICBjb252ZXJ0ZWRfYXMxID0gIiIuam9pbihBTkdMRV9DT01QTEVNRU5UU1tjXSBmb3IgYyBpbiBhbmdsZV9zdHIxKQoKICAgIGZvciBpIGluIHJhbmdlKG4pOgogICAgICAgIHJvdGF0ZWRfY2FzMSA9IGNvbnZlcnRlZF9hczFbaTpdICsgY29udmVydGVkX2FzMVs6aV0KCiAgICAgICAgaWYgcm90YXRlZF9jYXMxID09IGFuZ2xlX3N0cjIgb3IgKG5vdCBhbGxvd19yZWZsZWN0aW9ucyBhbmQgcm90YXRlZF9jYXMxWzo6LTFdID09IGFuZ2xlX3N0cjIpOgogICAgICAgICAgICAgICAgcmV0dXJuIFRydWUKCiAgICByZXR1cm4gRmFsc2UKCmRlZiBzb2x2ZShyb2RzLCBwb2ludD0oMCwgMCksIG1vdmVzPSIiLCBtb3ZlczI9IiIsIHZpc2l0ZWQ9Tm9uZSk6CiAgICBpZiBub3Qgcm9kczoKICAgICAgICBhbmdsZV9zdHIgPSB0b19hbmdsZXMobW92ZXMyKQogICAgICAgIAogICAgICAgIGlmIHBvaW50ID09ICgwLCAwKSBhbmQgYW5nbGVfc3RyLmNvdW50KCJBIikgLSBhbmdsZV9zdHIuY291bnQoIkMiKSA9PSA0OgogICAgICAgICAgICBmb3IgZiBpbiBGT1VORF9BTkdMRV9TVFJTOgogICAgICAgICAgICAgICAgaWYgZXF1YWwoZiwgYW5nbGVfc3RyKToKICAgICAgICAgICAgICAgICAgICBicmVhawoKICAgICAgICAgICAgZWxzZToKICAgICAgICAgICAgICAgIEZPVU5EX0FOR0xFX1NUUlMuYWRkKGFuZ2xlX3N0cikKICAgICAgICAgICAgICAgIHByaW50KG1vdmVzLCBhbmdsZV9zdHIpCgogICAgICAgIHJldHVybgoKICAgIGlmIG5vdCB2aXNpdGVkOgogICAgICAgIHZpc2l0ZWQgPSBzZXQoKQoKICAgIHIgPSByb2RzLnBvcCgwKQoKICAgIGZvciBtb3ZlLCBkaXJlY3Rpb24gaW4gWygociwwKSwgIlIiKSwgKCgwLHIpLCAiVSIpLCAoKC1yLDApLCAiTCIpLCAoKDAsLXIpLCAiRCIpXToKICAgICAgICBuZXdfcG9pbnQgPSAobW92ZVswXSArIHBvaW50WzBdLCBtb3ZlWzFdICsgcG9pbnRbMV0pCiAgICAgICAgYWRkZWRfdmlzaXRlZCA9IHNldCgpCiAgICAgICAgc2VhcmNoID0gVHJ1ZQoKICAgICAgICBmb3IgaSBpbiByYW5nZShtaW4ocG9pbnRbMF0sbmV3X3BvaW50WzBdKSwgbWF4KHBvaW50WzBdLG5ld19wb2ludFswXSkrMSk6CiAgICAgICAgICAgIGZvciBqIGluIHJhbmdlKG1pbihwb2ludFsxXSxuZXdfcG9pbnRbMV0pLCBtYXgocG9pbnRbMV0sbmV3X3BvaW50WzFdKSsxKToKICAgICAgICAgICAgICAgIGlmIChpLCBqKSAhPSBwb2ludDoKICAgICAgICAgICAgICAgICAgICBpZiAoaSwgaikgaW4gdmlzaXRlZDoKICAgICAgICAgICAgICAgICAgICAgICAgc2VhcmNoID0gRmFsc2UKCiAgICAgICAgICAgICAgICAgICAgICAgIGZvciBhIGluIGFkZGVkX3Zpc2l0ZWQ6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2aXNpdGVkLnJlbW92ZShhKQoKICAgICAgICAgICAgICAgICAgICAgICAgYWRkZWRfdmlzaXRlZCA9IHNldCgpICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICBicmVhawoKICAgICAgICAgICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgICAgICAgICB2aXNpdGVkLmFkZCgoaSwgaikpCiAgICAgICAgICAgICAgICAgICAgICAgIGFkZGVkX3Zpc2l0ZWQuYWRkKChpLCBqKSkKCiAgICAgICAgICAgIGlmIG5vdCBzZWFyY2g6CiAgICAgICAgICAgICAgICBicmVhawoKICAgICAgICBpZiBzZWFyY2g6CiAgICAgICAgICAgIHNvbHZlKHJvZHMsIG5ld19wb2ludCwgbW92ZXMgKyBkaXJlY3Rpb24sIG1vdmVzMiArIGRpcmVjdGlvbipyLCB2aXNpdGVkKQoKICAgICAgICBmb3IgYSBpbiBhZGRlZF92aXNpdGVkOgogICAgICAgICAgICB2aXNpdGVkLnJlbW92ZShhKQoKICAgIHJvZHMuaW5zZXJ0KDAsIHIpCgpzb2x2ZShbMV0qMTAp