in reply to Challenge: "Insanity" Cube Puzzle

The following runs in a fraction of second. I haven't looked at the other code contributions so I won't try to compare code complexity. (:

You can't change which color is opposite which color on the cubes. So each cube boils down to the 3 pairs of colors that are opposite each other on that cube. If we label the stack of cubes to be built with X, Y, and Z axes, then you can position each cube such that any of the three pairs shows on the X axis in either order and either of the remaining pairs shows on the Y axis in either order. It doesn't do any good to change the order in which the cubes are stacked. For the first cube, the only positions that matter are 3 of them, each cooresponding to a different pair of faces being hidden on the Z axis (the other positions would just boil down to duplicates where the stack is rotated or all 4 cubes on the stack are flipped along the same axis).

@cubes contains the four cubes, each as an array of color abbreviations grouped in the array as pairs of colors that are on opposite faces of the cube.

So we let the first cubes assume 3 different positions. We let each subsequent cube assume all 24 possible positions. For simplicity and speed, I precalculate arrays that show which face goes on which side. @base holds three positions that matter for the first cube. @full contains the mappings for all 24 orientations for subsequent cubes.

@side contains the colors showing on the sides of the stack as it is built, the first two colors showing on opposite sides of the X axis, the last two on the Y axis. setSides() adds the next 4 faces, adding one color to each side. If a duplicate color is found, then 0 is returned immediately. Otherwise, 1 is returned after all of the sides have been updated.

#!/usr/bin/perl -w use strict; my @cubes= map [/./g], 'ppgygr', 'rrprgy', 'prpyyg', 'ryrgpy'; my @sides= ( '', '', '', '' ); my @base= map [/./g], '0123', '0145', '2345'; my @full; # Populate @full: for my $base ( @base ) { my @perm= @$base; for( 0..1 ) { for( 0..1 ) { for( 0..1 ) { push @full, [ @perm ]; @perm[0,1,2,3]= @perm[2,3,0,1]; # Rotate 90deg; swap X +/Y } @perm[2,3]= @perm[3,2]; # Flip to reverse faces on Y axis } @perm[0,1]= @perm[1,0]; # Flip to reverse faces on X axis } die if "@perm" ne "@$base"; } # Try to explain format of the solution output: print "For cubes 1, 2, 3, and 4. The colors showing:\n"; print "frnt back left right\n"; print "1234 1234 1234 1234\n"; # Build the stack one cube at-a-time: for my $perm ( @base ) { next if ! setSides( 0, $perm ); for my $perm ( @full ) { next if ! setSides( 1, $perm ); for my $perm ( @full ) { next if ! setSides( 2, $perm ); for my $perm ( @full ) { if( setSides( 3, $perm ) ) { print "@sides\n"; } } } } } sub setSides { my( $pos, $perm )= @_; for my $cube ( $cubes[$pos] ) { for my $idx ( 0..3 ) { for my $side ( $sides[$idx] ) { for my $face ( $cube->[ $perm->[$idx] ] ) { substr( $side, $pos )= $face; return 0 if index( $side, $face ) < $pos; } } } } return 1; }

- tye