1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # This file is free software, which comes along with NIT. This software is
4 # distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
5 # without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
6 # PARTICULAR PURPOSE. You can modify it is you want, provided this header
7 # is kept unaltered, and a notification of the changes is added.
8 # You are allowed to redistribute it and sell it, alone or is a part of
13 private fun array1d_copy_to
(fromarr
: Array[Int], oarr
: Array[Int]) do
14 while oarr
.length
> fromarr
.length
do oarr
.pop
15 while oarr
.length
< fromarr
.length
do oarr
.push
0
16 fromarr
.copy_to
(0, fromarr
.length
, oarr
, 0)
19 private fun front_face
: Int do return 0
20 private fun left_face
: Int do return 1
21 private fun top_face
: Int do return 2
22 private fun right_face
: Int do return 3
23 private fun bottom_face
: Int do return 4
24 private fun back_face
: Int do return 5
26 private fun top_ln
: Int do return 0
27 private fun mid_ln
: Int do return 1
28 private fun bottom_ln
: Int do return 2
30 private fun left_col
: Int do return 0
31 private fun mid_col
: Int do return 1
32 private fun right_col
: Int do return 2
34 private fun clock
: Int do return 0
35 private fun counterclock
: Int do return 1
37 private fun square
: String do return once
"■"
41 # Returns a coloured square for a defined colour id
46 # * White (replaced with light gray) -> 1
49 # * Orange (replaced with purple) -> 4
52 private fun rubix_colour
: String do
53 if self == 0 then return square
.green
54 if self == 1 then return square
.light_gray
55 if self == 2 then return square
.red
56 if self == 3 then return square
.yellow
57 if self == 4 then return square
.purple
58 if self == 5 then return square
.blue
63 # In-memory representation of a Rubix Cube
65 # Faces are represented in memory as if they were a flattened cube like:
82 # All the commands detailed in the class respect the Singmaster notation
98 var faces
: Array[Array[Array[Int]]]
100 # Build a new Rubix Cube with a solved layout
102 var faces
= new Array[Array[Array[Int]]]
105 var face
= new Array[Array[Int]]
108 var line
= new Array[Int]
119 # Build a new Rubix Cube with a scrambled layout
121 # NOTE: The layout is not random, but scrambled nonetheless
123 var colours
= once
[0, 1, 2, 3, 4, 5]
125 var faces
= new Array[Array[Array[Int]]]
128 var face
= new Array[Array[Int]]
131 var line
= new Array[Int]
133 line
.add colours
[colour_pos
]
134 colour_pos
+= increment
135 if colour_pos
> 5 then
139 if colour_pos
< 0 then
150 # Reset the Rubix Cube to a solved position
163 # Checks if both objects are Rubix cubes and their content is equivalent
165 # NOTE: Rotationed versions are not yet considered equal
167 if not o
isa RubixCube then return false
168 for mf
in faces
, tf
in o
.faces
do
169 for ml
in mf
, tl
in tf
do
170 for mc
in ml
, tc
in tl
do if mc
!= tc
then return false
176 # Is `self` a solved Rubix Cube ?
177 fun is_solved
: Bool do
178 for face_id
in [0 .. 6[ do
179 var i
= faces
[face_id
]
180 var colour
= i
.first
.first
184 if ln
[k
] != colour
then return false
193 buf
.append
(single_face
(back_face
))
194 buf
.append
(single_face
(top_face
))
195 buf
.append
(three_faces
(left_face
, front_face
, right_face
))
196 buf
.append
(single_face
(bottom_face
))
200 private fun single_face
(face_id
: Int): Text do
202 var face
= faces
[face_id
]
205 b
.append
("{" " * 6}{ln[0].rubix_colour} {ln[1].rubix_colour} {ln[2].rubix_colour}{" " * 6}\n")
210 private fun three_faces
(face1
, face2
, face3
: Int): Text do
212 var face_ids
= [face1
, face2
, face3
]
217 b
.append
("{ln[0].rubix_colour} {ln[1].rubix_colour} {ln[2].rubix_colour} ")
224 private var rot_ln_buffer
= new Array[Array[Int]].with_capacity
(4)
225 private fun rotate_line
(ln_id
: Int, direction
: Int) do
226 var line_data
= rot_ln_buffer
227 if line_data
.is_empty
then for i
in [0 .. 4[ do line_data
.add
(new Array[Int])
228 array1d_copy_to
(faces
[front_face
][ln_id
], line_data
[0])
229 array1d_copy_to
(faces
[left_face
][ln_id
], line_data
[1])
230 array1d_copy_to
(faces
[back_face
][2 - ln_id
], line_data
[2])
231 array1d_copy_to
(faces
[right_face
][ln_id
], line_data
[3])
232 if direction
== counterclock
then
233 line_data
[3].swap_at
(0, 2)
234 line_data
[2].swap_at
(0, 2)
235 rot_ln_buffer
.rotate_left
236 else if direction
== clock
then
237 line_data
[1].swap_at
(0, 2)
238 line_data
[2].swap_at
(0, 2)
239 rot_ln_buffer
.rotate_right
243 array1d_copy_to
(line_data
[0], faces
[front_face
][ln_id
])
244 array1d_copy_to
(line_data
[1], faces
[left_face
][ln_id
])
245 array1d_copy_to
(line_data
[2], faces
[back_face
][2 - ln_id
])
246 array1d_copy_to
(line_data
[3], faces
[right_face
][ln_id
])
249 private var colbuf
= new Array[Int].with_capacity
(3)
250 private fun coldata
(face_id
: Int, col_id
: Int): Array[Int] do
251 if colbuf
.is_empty
then for i
in [0 .. 3[ do colbuf
.add
0
252 var face
= faces
[face_id
]
253 for i
in [0 .. 3[ do colbuf
[i
] = face
[i
][col_id
]
257 private fun set_coldata
(face_id
, col_id
: Int, coldata
: Array[Int]) do
258 var face
= faces
[face_id
]
259 for i
in [0 .. 3[ do face
[i
][col_id
] = coldata
[i
]
262 private var rot_col_buffer
= new Array[Array[Int]].with_capacity
(4)
263 private fun rotate_column
(col_id
: Int, direction
: Int) do
264 var col_data
= rot_col_buffer
265 if col_data
.is_empty
then for i
in [0 .. 4[ do col_data
.add
(new Array[Int])
266 array1d_copy_to
(coldata
(front_face
, col_id
), rot_col_buffer
[0])
267 array1d_copy_to
(coldata
(top_face
, col_id
), rot_col_buffer
[1])
268 array1d_copy_to
(coldata
(back_face
, col_id
), rot_col_buffer
[2])
269 array1d_copy_to
(coldata
(bottom_face
, col_id
), rot_col_buffer
[3])
270 if direction
== clock
then
271 rot_col_buffer
.rotate_left
272 else if direction
== counterclock
then
273 rot_col_buffer
.rotate_right
277 set_coldata
(front_face
, col_id
, rot_col_buffer
[0])
278 set_coldata
(top_face
, col_id
, rot_col_buffer
[1])
279 set_coldata
(back_face
, col_id
, rot_col_buffer
[2])
280 set_coldata
(bottom_face
, col_id
, rot_col_buffer
[3])
283 private var r90_cache
= new Array[Array[Int]]
284 private fun rotate_l90_face
(face_id
: Int) do
285 var lines
= r90_cache
286 if lines
.is_empty
then for i
in [0 .. 3[ do lines
.add
(new Array[Int])
287 array1d_copy_to
(faces
[face_id
][top_ln
], lines
[0])
288 array1d_copy_to
(faces
[face_id
][mid_ln
], lines
[1])
289 array1d_copy_to
(faces
[face_id
][bottom_ln
], lines
[2])
290 for i
in [0 .. 3[ do lines
[i
].swap_at
(0, 2)
291 set_coldata
(face_id
, left_col
, lines
[0])
292 set_coldata
(face_id
, mid_col
, lines
[1])
293 set_coldata
(face_id
, right_col
, lines
[2])
296 private fun rotate_r90_face
(face_id
: Int) do
297 var lines
= r90_cache
298 if lines
.is_empty
then for i
in [0 .. 3[ do lines
.add
(new Array[Int])
299 array1d_copy_to
(faces
[face_id
][top_ln
], lines
[0])
300 array1d_copy_to
(faces
[face_id
][mid_ln
], lines
[1])
301 array1d_copy_to
(faces
[face_id
][bottom_ln
], lines
[2])
302 set_coldata
(face_id
, right_col
, lines
[0])
303 set_coldata
(face_id
, mid_col
, lines
[1])
304 set_coldata
(face_id
, left_col
, lines
[2])
309 rotate_line
(top_ln
, clock
)
310 rotate_r90_face
(top_face
)
315 rotate_line
(top_ln
, counterclock
)
316 rotate_l90_face
(top_face
)
321 rotate_line
(bottom_ln
, counterclock
)
322 rotate_r90_face
(bottom_face
)
327 rotate_line
(bottom_ln
, clock
)
328 rotate_l90_face
(bottom_face
)
333 rotate_column
(left_col
, clock
)
334 rotate_r90_face
(left_face
)
339 rotate_column
(left_col
, counterclock
)
340 rotate_l90_face
(left_face
)
345 rotate_column
(right_col
, counterclock
)
346 rotate_r90_face
(right_face
)
351 rotate_column
(right_col
, clock
)
352 rotate_l90_face
(right_face
)
356 fun clock_M
do rotate_column
(mid_col
, clock
)
359 fun cclock_M
do rotate_column
(mid_col
, counterclock
)
362 fun clock_E
do rotate_line
(mid_ln
, counterclock
)
365 fun cclock_E
do rotate_line
(mid_ln
, clock
)
482 fun cube_Y_rotation
do
489 fun ccube_Y_rotation
do
496 fun cube_X_rotation
do
503 fun ccube_X_rotation
do
510 fun cube_Z_rotation
do
517 fun ccube_Z_rotation
do
523 # Applies a command `cmd` to `self`, returns the number of operations performed during the command
524 fun do_cmd
(cmd
: String): Int do
525 if cmd
== "" then return 0
527 var cmdln
= cmd
.length
528 if cmd
[cmdln
- 1] == '2' then
535 if cmd2
== '2' then cmd2
= '\0'
537 for i
in [1 .. iters
] do
544 else if cmd1 == 'L
' then
550 else if cmd1
== 'F' then
556 else if cmd1 == 'R
' then
562 else if cmd1
== 'B' then
568 else if cmd1 == 'D
' then
574 else if cmd1
== 'M' then
580 else if cmd1 == 'E
' then
586 else if cmd1
== 'S' then
592 else if cmd1 == 'u
' then
598 else if cmd1
== 'l' then
604 else if cmd1 == 'f
' then
610 else if cmd1
== 'r' then
616 else if cmd1 == 'b
' then
622 else if cmd1
== 'd' then
628 else if cmd1 == 'X
' then
634 else if cmd1
== 'Y' then
640 else if cmd1 == 'Z
' then