Python for cubing programs?

Here's a random script I wrote years ago, that's sort of cubing related http://ideone.com/mfVk3

based off of Badmephisto's Gripper from years past.

That's quite un-pythonic, though, more like Java forced into Python. As a kind of challenge, allow me to rewrite it so it's actually Python (though I kept the non-standard indentation):
http://ideone.com/8tzvWi

For example:

Code:
for x in range(0, len(things)):
    handle(things[x])

That's rather an example for what *not* to do. Python is really beautiful and the above makes it look ugly. Compare it to how it looks when done properly:

Code:
for thing in things:
    handle(thing)

(Or where appropriate, use comprehensions or map or whatever)
 
Last edited:
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? :)

fastest_snake_solve_ever.jpg


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.
 
Last edited:
Note, though, that that's an abomination extraordinaire, utterly abusing Python beyond belief :p

I rewrote it so it's actually Python (though I kept the non-standard bad indentation):
http://ideone.com/8tzvWi

Seriously, please don't showcase something like this:

Code:
for x in range(0, len(things)):
    handle(things[x])

That should never be shown/taught except explicitly as an example for what *not* to do. Python is really beautiful and the above makes it look ugly. Compare it to how it looks when done properly:

Code:
for thing in things:
    handle(thing)

(Or where appropriate, use comprehensions or map or whatever)

Oh yes, sub-par code should surely never be posted on the internet!
I am such shame for posting code that I wrote years ago in a short foray into a language.

[note that the above is mostly tongue in cheek. I think it's a bit much to call it an 'abomination extraodinaire' (insulting, useless, and non-constructive) but the code is admittedly poor]

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.

Wow, very neat. Thanks for sharing, but I'd love to see more. (aka. stop teasing and give us some proper source code!)
 
Oh yes, sub-par code should surely never be posted on the internet!
I am such shame for posting code that I wrote years ago in a short foray into a language.

[note that the above is mostly tongue in cheek. I think it's a bit much to call it an 'abomination extraodinaire' (insulting, useless, and non-constructive) but the code is admittedly poor]



Wow, very neat. Thanks for sharing, but I'd love to see more. (aka. stop teasing and give us some proper source code!)

Try refreshing your browser. You replied when I was still typing.

I didn't mean to hijack the Python thread here, I am looking to learn Python myself. Most of what I typed above is in the 4x4x4 Programming Discussion thread. I also have links to download the program in that area.

I would still like to see some Python source for a 4x4x4 solver since just reading over it I believe I can learn the syntax. I'd like to make a python version of my program for practice.
 
Oh yes, sub-par code should surely never be posted on the internet!
I am such shame for posting code that I wrote years ago in a short foray into a language.

[note that the above is mostly tongue in cheek. I think it's a bit much to call it an 'abomination extraodinaire' (insulting, useless, and non-constructive) but the code is admittedly poor]

Well it's not just sub-par, it's really very bad. It has almost nothing to do with Python. It also wasn't just posted, it was given to a beginner to possibly learn from it.

It's like someone asking for help with the cube and seriously being shown how to peel off the stickers.

Sorry if you felt insulted by my over-the-top introductory joke, though I do hope it's useful (by making clear that that program is bad and by perhaps preventing similar programs being posted for education), and I hope my rewritten program as well as the code snippets in my post are constructive.

Wow, very neat. Thanks for sharing, but I'd love to see more. (aka. stop teasing and give us some proper source code!)

Ugh, now he posted even more of it here. Can't that stay in his 4x4 solver thread? What is it doing here?

I would still like to see some Python source for a 4x4x4 solver

I think it would be quite slow. That's not really a job for Python.

But maybe you'd like to see a 3x3 simulator? Here's one (the program as a whole checks whether two given algorithms have the same effect, someone made a thread about that a while back), though admittedly it's not the most beginner-friendly example:

https://gist.github.com/pochmann/a70e314bbeb954b13ef5
 
Last edited:
Or use Perl and make it even neater:

Code:
 handle() foreach @things;

You have to say handle($_), no? Which makes it less neat, and longer than Python. But you can shorten "foreach" to just "for". Comparison then:

Code:
Perl:   handle($_) for @things;
Python: for t in things: handle(t)

I'm not sure Perl's is neater, and I don't miss it. Like I said, you could also use comprehensions or map or whatever. That example was just to show not unnecessarily using indices, and as you can see in the rewritten program, I did replace for-loops with comprehension and map. Where I do use a normal for-loop, I actually prefer a normal one over Perl's modifier one (though I acknowledge they and the other modifiers can be good), and then in Perl you'd have the parentheses and curly braces:

Code:
Perl vs. Python:

for (@things) {
    print($_);
    #domorestuff with $_
}

for t in things:
    print(t)
    #domorestuff with t

You could also do this, but it's rather abusive:
Code:
map(handle, things)
 
Last edited:
Well I think you have to say handle($_), no? Which makes it less neat, and longer than Python. But you can shorten "foreach" to just "for".
No because $_ is global. Not that it would be good programming to do it that way of course. In practice I'd pass it explicitly as you suggest (unless writing obtuse code for my own gratification).

I prefer "foreach" for iterating over a set as it better expresses the semantics.
 
Hey there, I am also learning Python as you are. My recommendation is to make something like a timer, and things that you have suggested in the post. Because you are a beginner, don't start out to complicated, do some research, when you learn more, you could make an artificial intelligence program to make a online Rubik's cube solver!

I hope that helped,


Sauce, :)
 
I learnt Python when I was 8... Someone I know made a program for 2x2x2. It was just making all possible states by doing a random move and add it if it's not already in the file... But this is not finding an optimal solve...
 
Hey Sauce,

Thanks for the tip...actually yesterday I set out on an adventure to write a program that would predict the outcome of a cube with a certain scramble. For a beginner like me, I think I actually got a lot done. Of course, progress was slow, and there were a few things I didn't understand, so I had to write everything in a very roundabout way. The program hasn't succeeded...yet. I will continue to further my skills in Python until I am more confident of a faster and better way to write the program.

Hey martinss,

Like I said above I tried to make a similar program to that of which you mentioned. I think finding the optimal solve will be lightyears more difficult than just predicting the outcome of a scramble.

Rainbow Flash
 
Last edited:
I did some stuff in a similar language called q for a work internship a while ago. Here's a relatively efficient prime checker (checked 1125899839733759 in 609 ms):
Code:
isPrime2:{$[x<2;0b;0=x mod 2;x=2;0<>min x mod 1+2*1_til(floor 1+sqrt x)div 2]}
 
I'm working on a letter pair memo program for BLD.

So far it will:

Create a notepad file containing AB - XW (deleting all AA, BB, etc...)

If notepad file exists, import that.

Prompt user for how many pairs to memo (x).

Repeat this sequence x number of times
1. randomly select and display a letter pair
2. allow user to add a "hint"for future memorization (this hint would be your memo for that pair, like MJ hint might be Michael Jordan)
3. If user types anything, the hint will be added to the list for that pair and the notepad will be updated
If user types nothing, it will just move on
4. Append the pair onto a string that starts empty (basically loading the entire word pair sequence as the loop goes)

Clear screen and ask user for the answer.

Removes all white spaces from answer, and also capitalize the answer (in case the user doesn't)

Compare answer to the pair string, if correct, display "correct", if not, display "You typed xxxx, it was actually xxxxx"

Simple program. I'm working on getting it into some kind of GUI with buttons, but so far that has been a nightmare. I can't seem to get the loop to wait for a button click (unlike in text, where it can simply prompt the user to pause the loop).

I also want to add a timer, but that's down the road.
 
I'm working on a letter pair memo program for BLD.

So far it will:

Create a notepad file containing AB - XW (deleting all AA, BB, etc...)

If notepad file exists, import that.

Prompt user for how many pairs to memo (x).

Repeat this sequence x number of times
1. randomly select and display a letter pair
2. allow user to add a "hint"for future memorization (this hint would be your memo for that pair, like MJ hint might be Michael Jordan)
3. If user types anything, the hint will be added to the list for that pair and the notepad will be updated
If user types nothing, it will just move on
4. Append the pair onto a string that starts empty (basically loading the entire word pair sequence as the loop goes)

Clear screen and ask user for the answer.

Removes all white spaces from answer, and also capitalize the answer (in case the user doesn't)

Compare answer to the pair string, if correct, display "correct", if not, display "You typed xxxx, it was actually xxxxx"

Simple program. I'm working on getting it into some kind of GUI with buttons, but so far that has been a nightmare. I can't seem to get the loop to wait for a button click (unlike in text, where it can simply prompt the user to pause the loop).

I also want to add a timer, but that's down the road.

Hey, this is a good idea. Start a thread about it once your done! I'll try making a version too, although I'm not good at any GUI stuff.
 
I'm working on getting it into some kind of GUI with buttons, but so far that has been a nightmare. I can't seem to get the loop to wait for a button click (unlike in text, where it can simply prompt the user to pause the loop).

Sounds like you're doing it wrong. Typically you build the GUI, register actions that will be called when something happens (like a button click), and then call the GUI's mainloop, i.e., giving up control, not still running your own loop. What GUI package are you using?
 
Back
Top