Well, Python is a Very High Level programming language, and will naturally be factors slower than something written in C/C++.
That said, people have done some pretty fast things in other high-level programming languages (hell, JavaScript is surprising everyone with some performance gains!).
When it comes down to things, though, the algorithms you use are of course the most important thing.
I'd love to see that board design and the 6 lines that execute, in any language.
[as far as I've seen, no decent 444 solver exists in python]
How is this for fast?
I have 3 experimental versions of the program. One is slow and finds every possible solve to a scramble. One is fast and finds multiple solutions. One is ridiculously fast (shown above) and finds and least one, possibly more than one, optimal solution at the expense of doing a great deal of pruning.
It is so fast because each side of the 4x4x4 cube is just one 64-bit integer, 4 bits per "sticker," and I use 64-bit shifts, ANDs, and ORs to make moves, instead of using matrix swap operations.
Do you mean 6 executed or 6 lines within a loop? I'd like to see that too.
I'm also interested in any examples of cube-related code in Python. Looking at examples is probably the best way of getting a feel for a language.
Board layout...
Code:
BYTE 01 BYTE 02 BYTE 03 BYTE 04 BYTE 05 BYTE 06 BYTE 07 BYTE 08
<-------------> <-------------> <-------------> <-------------> <-------------> <-------------> <-------------> <------------->
0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 = TOP
0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 = FRONT
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 = RIGHT
0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 = BOTTOM
1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 = BACK
1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 = LEFT
So each color sticker has a different number. Top = 2, Front = 3, Right = 5, Bottom = 7, Back = 11, Left = 13. Shown above in base-2, all 1's and 0's, using 4 bits per color.
So 2 = 0010, 3 = 0011, 5 = 0101, 7 = 0111, 11 = 1101, 13 = 1011.
Each row of 64 1's and 0's is one variable 64 bits in length. So making a move on the 4x4x4 cube becomes easy. Just shift and move the bits in clusters of 4 to their new destinations. The code below makes the move U on the 4x4x4 cube. I call it "T+" since that is how I used to write moves when I did not know the notation.
Code:
BITBOARD_4x4x4_CUBE T_PLUS(BITBOARD_4x4x4_CUBE original_4x4x4_cube)
{
BITBOARD_4x4x4_CUBE new_cube;
/**************************************************************************/
/* Rotating the top will change something on every face except the bottom */
/**************************************************************************/
new_cube._4x4x4_bottom = original_4x4x4_cube._4x4x4_bottom;
/******************************************************************************************/
/* Entire row of cubes moves from right -----> front -----> left -----> back -----> right */
/* new front = old right; new right = old back; new back = old left; new left = old front */
/******************************************************************************************/
new_cube._4x4x4_front = (original_4x4x4_cube._4x4x4_front & BITMASK_CUBE_FACE_NOT_ROW_01) | (original_4x4x4_cube._4x4x4_right & BITMASK_CUBE_FACE_ROW_01);
new_cube._4x4x4_right = (original_4x4x4_cube._4x4x4_right & BITMASK_CUBE_FACE_NOT_ROW_01) | (original_4x4x4_cube._4x4x4_back & BITMASK_CUBE_FACE_ROW_01);
new_cube._4x4x4_back = (original_4x4x4_cube._4x4x4_back & BITMASK_CUBE_FACE_NOT_ROW_01) | (original_4x4x4_cube._4x4x4_left & BITMASK_CUBE_FACE_ROW_01);
new_cube._4x4x4_left = (original_4x4x4_cube._4x4x4_left & BITMASK_CUBE_FACE_NOT_ROW_01) | (original_4x4x4_cube._4x4x4_front & BITMASK_CUBE_FACE_ROW_01);
/*********************************************************************************/
/* Rotate the TOP */
/*********************************************************************************/
/* */
/* THESE CUBE LOCATIONS BECOME.... THESE CUBE LOCATIONS */
/* */
/* */
/*********************************/ /*********************************/
/* 01 * 02 * 03 * 04 */ /* 13 * 09 * 05 * 01 */
/*********************************/ /*********************************/
/* 05 * 06 * 07 * 08 */ /* 14 * 10 * 06 * 02 */
/*********************************/ /*********************************/
/* 09 * 10 * 11 * 12 */ /* 15 * 11 * 07 * 03 */
/*********************************/ /*********************************/
/* 13 * 14 * 15 * 16 */ /* 16 * 12 * 08 * 04 */
/*********************************/ /*********************************/
/* */
/* */
/*********************************************************************************/
new_cube._4x4x4_top = ((original_4x4x4_cube._4x4x4_top & BITMASK_CUBE_FACE_SQUARE_13) << 48) | \
((original_4x4x4_cube._4x4x4_top & BITMASK_CUBE_FACE_SQUARE_09) << 28) | \
((original_4x4x4_cube._4x4x4_top & BITMASK_CUBE_FACE_SQUARE_05) << 8) | \
((original_4x4x4_cube._4x4x4_top & BITMASK_CUBE_FACE_SQUARE_01) >> 12) | \
((original_4x4x4_cube._4x4x4_top & BITMASK_CUBE_FACE_SQUARE_14) << 36) | \
((original_4x4x4_cube._4x4x4_top & BITMASK_CUBE_FACE_SQUARE_10) << 16) | \
((original_4x4x4_cube._4x4x4_top & BITMASK_CUBE_FACE_SQUARE_06) >> 4) | \
((original_4x4x4_cube._4x4x4_top & BITMASK_CUBE_FACE_SQUARE_02) >> 24) | \
((original_4x4x4_cube._4x4x4_top & BITMASK_CUBE_FACE_SQUARE_15) << 24) | \
((original_4x4x4_cube._4x4x4_top & BITMASK_CUBE_FACE_SQUARE_11) << 4) | \
((original_4x4x4_cube._4x4x4_top & BITMASK_CUBE_FACE_SQUARE_07) >> 16) | \
((original_4x4x4_cube._4x4x4_top & BITMASK_CUBE_FACE_SQUARE_03) >> 36) | \
((original_4x4x4_cube._4x4x4_top & BITMASK_CUBE_FACE_SQUARE_16) << 12) | \
((original_4x4x4_cube._4x4x4_top & BITMASK_CUBE_FACE_SQUARE_12) >> 8) | \
((original_4x4x4_cube._4x4x4_top & BITMASK_CUBE_FACE_SQUARE_08) >> 28) | \
((original_4x4x4_cube._4x4x4_top & BITMASK_CUBE_FACE_SQUARE_04) >> 48);
return new_cube;
}
I just had to create bit "masks" to use as selectors.
Code:
#define BITMASK_CUBE_FACE_SQUARE_01 0xF000000000000000
#define BITMASK_CUBE_FACE_SQUARE_02 0x0F00000000000000
#define BITMASK_CUBE_FACE_SQUARE_03 0x00F0000000000000
#define BITMASK_CUBE_FACE_SQUARE_04 0x000F000000000000
#define BITMASK_CUBE_FACE_SQUARE_05 0x0000F00000000000
#define BITMASK_CUBE_FACE_SQUARE_06 0x00000F0000000000
#define BITMASK_CUBE_FACE_SQUARE_07 0x000000F000000000
#define BITMASK_CUBE_FACE_SQUARE_08 0x0000000F00000000
#define BITMASK_CUBE_FACE_SQUARE_09 0x00000000F0000000
#define BITMASK_CUBE_FACE_SQUARE_10 0x000000000F000000
#define BITMASK_CUBE_FACE_SQUARE_11 0x0000000000F00000
#define BITMASK_CUBE_FACE_SQUARE_12 0x00000000000F0000
#define BITMASK_CUBE_FACE_SQUARE_13 0x000000000000F000
#define BITMASK_CUBE_FACE_SQUARE_14 0x0000000000000F00
#define BITMASK_CUBE_FACE_SQUARE_15 0x00000000000000F0
#define BITMASK_CUBE_FACE_SQUARE_16 0x000000000000000F
#define BITMASK_CUBE_FACE_ROW_01 0xFFFF000000000000
#define BITMASK_CUBE_FACE_ROW_02 0x0000FFFF00000000
#define BITMASK_CUBE_FACE_ROW_03 0x00000000FFFF0000
#define BITMASK_CUBE_FACE_ROW_04 0x000000000000FFFF
#define BITMASK_CUBE_FACE_NOT_ROW_01 0x0000FFFFFFFFFFFF
#define BITMASK_CUBE_FACE_NOT_ROW_02 0xFFFF0000FFFFFFFF
#define BITMASK_CUBE_FACE_NOT_ROW_03 0xFFFFFFFF0000FFFF
#define BITMASK_CUBE_FACE_NOT_ROW_04 0xFFFFFFFFFFFF0000
#define BITMASK_CUBE_FACE_COL_01 0xF000F000F000F000
#define BITMASK_CUBE_FACE_NOT_COL_01 0x0FFF0FFF0FFF0FFF
#define BITMASK_CUBE_FACE_COL_02 0x0F000F000F000F00
#define BITMASK_CUBE_FACE_NOT_COL_02 0xF0FFF0FFF0FFF0FF
#define BITMASK_CUBE_FACE_COL_03 0x00F000F000F000F0
#define BITMASK_CUBE_FACE_NOT_COL_03 0xFF0FFF0FFF0FFF0F
#define BITMASK_CUBE_FACE_COL_04 0x000F000F000F000F
#define BITMASK_CUBE_FACE_NOT_COL_04 0xFFF0FFF0FFF0FFF0
Every "&" in C is a Bit-AND, which is like multiplication in base-2. 1x0 = 0, 1x1 = 1, so when the patterns line up, only those marked with 1 will be passed on. Those marked with 0 are ignored.
Every "|" in C is a Bit-OR, which is like addition without a carry in base-2. 1+0 = 1, 1+1 = 1, 0+0 = 0, so when you see a 1 or a 0, the 1 will be passed on.
0xF000000000000000 in base-16 = 1111 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 in base-2. So when you take a 64-bit cube face, and bit-AND with that pattern, you only get the one cube on the top-left of the 16. If you want all of the cubes on in the top row, bit and with 0xFFFF000000000000. The next row down is 0x0000FFFF00000000 which is "skipping" the first 4, ignoring the last 4x3 bits, and grabbing the bits in between.