-
Notifications
You must be signed in to change notification settings - Fork 18
/
Copy pathcube.py
222 lines (211 loc) · 11.4 KB
/
cube.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
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
from random import randint, choice
class RubiksCube:
"""
Class containing the rubiks cube code
"""
def __init__(
self,
n = 3,
colours = ['w', 'o', 'g', 'r', 'b', 'y'],
state = None
):
"""
Input: n - integer representing the width and height of the rubiks cube
colours - list containing the first letter of ever colour you wish to use (Default = ['w', 'o', 'g', 'r', 'b', 'y']) [OPTIONAL]
state - string representing the current state of the rubix cube (Default = None) [OPTIONAL]
Description: Initialize the rubiks cube
Output: None
"""
if state is None:
self.n = n
self.colours = colours
self.reset()
else:
self.n = int((len(state) / 6) ** (.5))
self.colours = []
self.cube = [[[]]]
for i, s in enumerate(state):
if s not in self.colours: self.colours.append(s)
self.cube[-1][-1].append(s)
if len(self.cube[-1][-1]) == self.n and len(self.cube[-1]) < self.n:
self.cube[-1].append([])
elif len(self.cube[-1][-1]) == self.n and len(self.cube[-1]) == self.n and i < len(state) - 1:
self.cube.append([[]])
def reset(self):
"""
Input: None
Description: Reset the cube to its inital state
Output: None
"""
self.cube = [[[c for x in range(self.n)] for y in range(self.n)] for c in self.colours]
def solved(self):
"""
Input: None
Description: Determine if the cube is solved or not
Output: boolean representing if the cube is solved or not
"""
for side in self.cube:
hold = []
check = True
for row in side:
if len(set(row)) == 1:
hold.append(row[0])
else:
check = False
break
if check == False:
break
if len(set(hold)) > 1:
check = False
break
return check
def stringify(self):
"""
Input: None
Description: Create string representation of the current state of the cube
Output: string representing the cube current state
"""
return ''.join([i for r in self.cube for s in r for i in s])
def shuffle(self, l_rot = 5, u_rot = 100):
"""
Input: l_rot - integer representing the lower bounds of amount of moves (Default = 5) [OPTIONAL]
u_rot - integer representing the upper bounds of amount of moves (Default = 100) [OPTIONAL]
Description: Shuffles rubiks cube to random solvable state
Output: None
"""
moves = randint(l_rot, u_rot)
actions = [
('h', 0),
('h', 1),
('v', 0),
('v', 1),
('s', 0),
('s', 1)
]
for i in range(moves):
a = choice(actions)
j = randint(0, self.n - 1)
if a[0] == 'h':
self.horizontal_twist(j, a[1])
elif a[0] == 'v':
self.vertical_twist(j, a[1])
elif a[0] == 's':
self.side_twist(j, a[1])
def show(self):
"""
Input: None
Description: Show the rubiks cube
Output: None
"""
spacing = f'{" " * (len(str(self.cube[0][0])) + 2)}'
l1 = '\n'.join(spacing + str(c) for c in self.cube[0])
l2 = '\n'.join(' '.join(str(self.cube[i][j]) for i in range(1,5)) for j in range(len(self.cube[0])))
l3 = '\n'.join(spacing + str(c) for c in self.cube[5])
print(f'{l1}\n\n{l2}\n\n{l3}')
def horizontal_twist(self, row, direction):
"""
Input: row - integer representing which row you would like to twist
direction - boolean representing if you want to twist right or left [left - 0, right - 1]
Description: Twist desired row of rubiks cube
Output: None
"""
if row < len(self.cube[0]):
if direction == 0: #Twist left
self.cube[1][row], self.cube[2][row], self.cube[3][row], self.cube[4][row] = (self.cube[2][row],
self.cube[3][row],
self.cube[4][row],
self.cube[1][row])
elif direction == 1: #Twist right
self.cube[1][row], self.cube[2][row], self.cube[3][row], self.cube[4][row] = (self.cube[4][row],
self.cube[1][row],
self.cube[2][row],
self.cube[3][row])
else:
print(f'ERROR - direction must be 0 (left) or 1 (right)')
return
#Rotating connected face
if direction == 0: #Twist left
if row == 0:
self.cube[0] = [list(x) for x in zip(*reversed(self.cube[0]))] #Transpose top
elif row == len(self.cube[0]) - 1:
self.cube[5] = [list(x) for x in zip(*reversed(self.cube[5]))] #Transpose bottom
elif direction == 1: #Twist right
if row == 0:
self.cube[0] = [list(x) for x in zip(*self.cube[0])][::-1] #Transpose top
elif row == len(self.cube[0]) - 1:
self.cube[5] = [list(x) for x in zip(*self.cube[5])][::-1] #Transpose bottom
else:
print(f'ERROR - desired row outside of rubiks cube range. Please select a row between 0-{len(self.cube[0])-1}')
return
def vertical_twist(self, column, direction):
"""
Input: column - integer representing which column you would like to twist
direction - boolean representing if you want to twist up or down [down - 0, up - 1]
Description: Twist desired column of rubiks cube
Output: None
"""
if column < len(self.cube[0]):
for i in range(len(self.cube[0])):
if direction == 0: #Twist down
self.cube[0][i][column], self.cube[2][i][column], self.cube[4][-i-1][-column-1], self.cube[5][i][column] = (self.cube[4][-i-1][-column-1],
self.cube[0][i][column],
self.cube[5][i][column],
self.cube[2][i][column])
elif direction == 1: #Twist up
self.cube[0][i][column], self.cube[2][i][column], self.cube[4][-i-1][-column-1], self.cube[5][i][column] = (self.cube[2][i][column],
self.cube[5][i][column],
self.cube[0][i][column],
self.cube[4][-i-1][-column-1])
else:
print(f'ERROR - direction must be 0 (down) or 1 (up)')
return
#Rotating connected face
if direction == 0: #Twist down
if column == 0:
self.cube[1] = [list(x) for x in zip(*self.cube[1])][::-1] #Transpose left
elif column == len(self.cube[0]) - 1:
self.cube[3] = [list(x) for x in zip(*self.cube[3])][::-1] #Transpose right
elif direction == 1: #Twist up
if column == 0:
self.cube[1] = [list(x) for x in zip(*reversed(self.cube[1]))] #Transpose left
elif column == len(self.cube[0]) - 1:
self.cube[3] = [list(x) for x in zip(*reversed(self.cube[3]))] #Transpose right
else:
print(f'ERROR - desired column outside of rubiks cube range. Please select a column between 0-{len(self.cube[0])-1}')
return
def side_twist(self, column, direction):
"""
Input: column - integer representing which column you would like to twist
direction - boolean representing if you want to twist up or down [down - 0, up - 1]
Description: Twist desired side column of rubiks cube
Output: None
"""
if column < len(self.cube[0]):
for i in range(len(self.cube[0])):
if direction == 0: #Twist down
self.cube[0][column][i], self.cube[1][-i-1][column], self.cube[3][i][-column-1], self.cube[5][-column-1][-1-i] = (self.cube[3][i][-column-1],
self.cube[0][column][i],
self.cube[5][-column-1][-1-i],
self.cube[1][-i-1][column])
elif direction == 1: #Twist up
self.cube[0][column][i], self.cube[1][-i-1][column], self.cube[3][i][-column-1], self.cube[5][-column-1][-1-i] = (self.cube[1][-i-1][column],
self.cube[5][-column-1][-1-i],
self.cube[0][column][i],
self.cube[3][i][-column-1])
else:
print(f'ERROR - direction must be 0 (down) or 1 (up)')
return
#Rotating connected face
if direction == 0: #Twist down
if column == 0:
self.cube[4] = [list(x) for x in zip(*reversed(self.cube[4]))] #Transpose back
elif column == len(self.cube[0]) - 1:
self.cube[2] = [list(x) for x in zip(*reversed(self.cube[2]))] #Transpose top
elif direction == 1: #Twist up
if column == 0:
self.cube[4] = [list(x) for x in zip(*self.cube[4])][::-1] #Transpose back
elif column == len(self.cube[0]) - 1:
self.cube[2] = [list(x) for x in zip(*self.cube[2])][::-1] #Transpose top
else:
print(f'ERROR - desired column outside of rubiks cube range. Please select a column between 0-{len(self.cube[0])-1}')
return