-
Notifications
You must be signed in to change notification settings - Fork 22
/
Copy pathcubie.py
200 lines (166 loc) · 6.92 KB
/
cubie.py
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# ######### The 2x2x2 cube on the cubie level is described by the permutation and orientations of the corners ##########
from defs import cornerFacelet, cornerColor, N_CORNERS, N_TWIST
from enums import Color, Corner as Co
import face
from misc import rotate_left, rotate_right
from random import randrange
# ################## the basic six cube moves described by permutations and changes in orientation #####################
# Up-move
cpU = [Co.UBR, Co.URF, Co.UFL, Co.ULB, Co.DRB, Co.DFR, Co.DLF, Co.DBL]
coU = [0, 0, 0, 0, 0, 0, 0, 0]
# Right-move
cpR = [Co.DFR, Co.UFL, Co.ULB, Co.URF, Co.UBR, Co.DRB, Co.DLF, Co.DBL] # permutation of the corners
coR = [2, 0, 0, 1, 2, 1, 0, 0] # changes of the orientations of the corners
# Front-move
cpF = [Co.UFL, Co.DLF, Co.ULB, Co.UBR, Co.DRB, Co.URF, Co.DFR, Co.DBL]
coF = [1, 2, 0, 0, 0, 2, 1, 0]
########################################################################################################################
CUBE_OK = True
class CubieCube:
"""Represents a 2x2x2 cube on the cubie level with 8 corner cubies and the corner orientations.
Is also used to represent the 18 cube moves.
"""
def __init__(self, cp=None, co=None):
"""
Initializes corners and edges.
:param cp: corner permutation
:param co: corner orientation
"""
if cp is None:
self.cp = [Co(i) for i in range(8)] # You may not put this as the default two lines above!
else:
self.cp = cp[:]
if co is None:
self.co = [0] * 8
else:
self.co = co[:]
def __str__(self):
"""Prints string for a cubie cube."""
s = ''
for i in Co:
s = s + '(' + str(self.cp[i]) + ',' + str(self.co[i]) + ')'
return s
def __eq__(self, other):
"""Defines equality of two cubie cubes."""
if self.cp == other.cp and self.co == other.co:
return True
else:
return False
def to_facelet_cube(self):
"""Returns a facelet representation of the cube."""
fc = face.FaceCube()
for i in Co:
j = self.cp[i] # corner j is at corner position i
ori = self.co[i] # orientation of C j at position i
for k in range(3):
fc.f[cornerFacelet[i][(k + ori) % 3]] = cornerColor[j][k]
return fc
def multiply(self, b):
"""Multiplies this cubie cube with another cubie cube b. Does not change b."""
c_perm = [0] * 8
c_ori = [0] * 8
ori = 0
for c in Co:
c_perm[c] = self.cp[b.cp[c]]
ori_a = self.co[b.cp[c]]
ori_b = b.co[c]
if ori_a < 3 and ori_b < 3: # two regular cubes
ori = ori_a + ori_b
if ori >= 3:
ori -= 3
elif ori_a < 3 <= ori_b: # cube b is in a mirrored state
ori = ori_a + ori_b
if ori >= 6:
ori -= 3 # the composition also is in a mirrored state
elif ori_a >= 3 > ori_b: # cube a is in a mirrored state
ori = ori_a - ori_b
if ori < 3:
ori += 3 # the composition is a mirrored cube
elif ori_a >= 3 and ori_b >= 3: # if both cubes are in mirrored states
ori = ori_a - ori_b
if ori < 0:
ori += 3 # the composition is a regular cube
c_ori[c] = ori
for c in Co:
self.cp[c] = c_perm[c]
self.co[c] = c_ori[c]
def inv_cubie_cube(self, d):
"""Stores the inverse of this cubie cube in d."""
for c in Co:
d.cp[self.cp[c]] = c
for c in Co:
ori = self.co[d.cp[c]]
if ori >= 3:
d.co[c] = ori
else:
d.co[c] = -ori
if d.co[c] < 0:
d.co[c] += 3
# ###################################### coordinates for 2x2x2 cube #################################################
def get_corntwist(self):
"""The twist of the 8 corners. 0 <= twist < 729. The DBL-corner is fixed."""
ret = 0
for i in range(Co.URF, Co.DLF):
ret = 3 * ret + self.co[i]
return ret
def set_cornertwist(self, twist):
twistparity = 0
for i in range(Co.DLF - 1, Co.URF - 1, -1):
self.co[i] = twist % 3
twistparity += self.co[i]
twist //= 3
self.co[Co.DLF] = ((3 - twistparity % 3) % 3)
def get_cornperm(self):
"""The permutation of the 8 corners. 0 <= corners < 5040. The DLB_corner is fixed."""
perm = list(self.cp) # duplicate cp
b = 0
for j in range(Co.DBL, Co.URF, -1):
k = 0
while perm[j] != j:
rotate_left(perm, 0, j)
k += 1
b = (j + 1) * b + k
return b
def set_corners(self, idx):
self.cp = [i for i in Co]
for j in Co:
k = idx % (j + 1)
idx //= j + 1
while k > 0:
rotate_right(self.cp, 0, j)
k -= 1
# ############################## end coordinates for 2x2x2 cube ########################################
# #################################### other usefull functions #########################################
def randomize(self):
"""Generates a random cube. The probability is the same for all possible states."""
self.set_corners(randrange(N_CORNERS))
self.set_cornertwist(randrange(N_TWIST))
def verify(self):
"""Checks if cubiecube is valid"""
corner_count = [0] * 8
for i in Co:
corner_count[self.cp[i]] += 1
for i in Co:
if corner_count[i] != 1:
return 'Error: Some corners are undefined.'
s = 0
for i in Co:
s += self.co[i]
if s % 3 != 0:
return 'Error: Total corner twist is wrong.'
return CUBE_OK
########################################################################################################################
# ################################## these cubes represent the basic cube moves ########################################
basicMoveCube = [0] * 6
basicMoveCube[Color.U] = CubieCube(cpU, coU)
basicMoveCube[Color.R] = CubieCube(cpR, coR)
basicMoveCube[Color.F] = CubieCube(cpF, coF)
########################################################################################################################
# ################################# these cubes represent the all 9 cube moves ########################################
moveCube = [0] * 9
for c1 in [Color.U, Color.R, Color.F]:
cc = CubieCube()
for k1 in range(3):
cc.multiply(basicMoveCube[c1])
moveCube[3 * c1 + k1] = CubieCube(cc.cp, cc.co)
########################################################################################################################