Skip to content

Instantly share code, notes, and snippets.

@robertcampion
Created May 24, 2016 21:36
Show Gist options
  • Save robertcampion/44777a3134adff3e4e42ff94e5c63c31 to your computer and use it in GitHub Desktop.
Save robertcampion/44777a3134adff3e4e42ff94e5c63c31 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
import itertools
import operator
import time
import math
# constants
format_str = r'''
D----------------- A -----------------D
\ ? / \ ? / \ ? // \\ ? / \ ? / \ ? /
\ / ? \ / ? \ // ? \\ / ? \ / ? \ /
\----(1)----//-----\\----(3)----/
\ ? / \ ? // \ ? / \\ ? / \ ? /
\ / ? \ // ? \ / ? \\ / ? \ /
\-----//----(2)----\\-----/
\ ? // \ ? / \ ? / \\ ? /
\ // ? \ / ? \ / ? \\ /
B ----------------- C
B-----------------C
\ ? / \ ? / \ ? /
\ / ? \ / ? \ /
\----(4)----/
\ ? / \ ? /
\ / ? \ /
\-----/
\ ? /
\ /
D
'''
format_str = format_str.replace('?', '{}')
# function definitions
def to_tip_faces(p):
return [[p[0][0], p[1][0], p[3][0]],
[p[0][1], p[1][1], p[2][0]],
[p[0][2], p[2][1], p[3][1]],
[p[1][2], p[2][2], p[3][2]],
[], [], [], []]
def to_vertex_faces(p):
return [[p[0][0], p[1][0], p[3][0]],
[p[0][1], p[1][1], p[2][0]],
[p[0][2], p[2][1], p[3][1]],
[p[1][2], p[2][2], p[3][2]],
[p[0][0], p[0][1], p[0][2]],
[p[1][0], p[1][1], p[1][2]],
[p[2][0], p[2][1], p[2][2]],
[p[3][0], p[3][1], p[3][2]]]
def to_edge_faces(p):
return [[p[0][0], p[1][0], p[2][0]],
[p[0][1], p[3][0], p[4][0]],
[p[1][1], p[3][1], p[5][0]],
[p[2][1], p[4][1], p[5][1]],
[p[0][0], p[0][1], p[1][0], p[1][1], p[3][0], p[3][1]],
[p[0][0], p[0][1], p[2][0], p[2][1], p[4][0], p[4][1]],
[p[3][0], p[3][1], p[4][0], p[4][1], p[5][0], p[5][1]],
[p[1][0], p[1][1], p[2][0], p[2][1], p[5][0], p[5][1]]]
def rotations(l):
return [l[i:] + l[:i] for i in range(len(l))]
def no_duplicates(l):
return all(len(subl) == len(set(subl)) for subl in l)
def perm_parity(l):
''' http://code.activestate.com/recipes/578227 '''
lst = list(l)
parity = 1
for i in range(0,len(lst)-1):
if lst[i] != i:
parity *= -1
mn = min(range(i,len(lst)), key=lst.__getitem__)
lst[i],lst[mn] = lst[mn],lst[i]
return parity
def permute(l, p):
return [l[i] for i in p]
def combine_states(*args):
return filter(no_duplicates, map(lambda x: list(map(operator.concat, *x)), itertools.product(*args)))
# precomputation
edge_flips = [f for f in itertools.product([0, 1], repeat=6) if sum(f) % 2 == 0]
edge_permutations = [p for p in itertools.permutations(range(6)) if perm_parity(p) == 1]
# solving
search_size = math.factorial(9)
count = 0
found = 0
def print_progress():
duration = time.time() - start_time
m, s = divmod(duration, 60)
h, m = divmod(m, 60)
print('found {} solutions'.format(found))
print('searched {:,d}/{:,d} states ({:.1%}) in {:d}:{:02d}:{:04.1f} (avg. {:.1f} ms)'
.format(count,search_size,count/search_size,int(h),int(m),s,1000*duration/count))
start_time = time.time()
try:
for face4 in itertools.permutations(range(1,10)):
tips = [[1, 4, 9], [5, 1, face4[0]], [6, 4, face4[1]], [7, 2, face4[2]]]
vertices = [[8, 3, 5], [2, 9, face4[3]], [5, 3, face4[4]], [3, 8, face4[5]]]
edges = [[4, 7], [9, 1], [6, face4[6]], [2, 6], [8, face4[7]], [7, face4[8]]]
tip_states = filter(no_duplicates,
map(to_tip_faces,
itertools.product(*map(rotations, tips))
)
)
vertex_states = filter(no_duplicates,
map(to_vertex_faces,
itertools.product(*map(rotations, vertices))
)
)
edge_orientations = [
[
list(reversed(x)) if r else x
for x, r in zip(edges, f)
]
for f in edge_flips
]
edge_states = filter(no_duplicates,
map(to_edge_faces,
itertools.starmap(permute,
itertools.product(edge_orientations, edge_permutations)
)
)
)
corner_states = combine_states(tip_states, vertex_states)
states = combine_states(corner_states, edge_states)
count += 1
try:
s = states.__next__()
except StopIteration:
continue # no solutions
try:
states.__next__()
continue # more than one solution
except StopIteration:
pass
found += 1
print_progress()
print(format_str.format(s[0][2], s[0][7], s[0][0], s[2][0], s[2][6], s[2][2], s[0][5], s[0][3], s[1][0], s[2][3], s[2][5], s[0][8], s[0][6], s[1][3], s[2][7], s[2][8], s[0][4], s[1][6], s[1][7], s[2][4], s[0][1], s[1][4], s[1][5], s[2][1], s[1][1], s[1][8], s[1][2], s[3][0], s[3][7], s[3][1], s[3][3], s[3][4], s[3][6], s[3][8], s[3][5], s[3][2]))
print('finished')
except KeyboardInterrupt:
print('stopping')
print_progress()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment