. . . x * * * (row 2, bit value 4) . . . * * * * (row 1, bit value 2) . * * . . . * (row 0, bit value 1) #### # swap rows 0 and 1 . x . . * * * . . * * . . * . * . . * * * $args = [ 1, 1, 2, 0, 0, 2, 0, 1 ] $height = 2, $v = 1 #### # .. and now swap rows 1 and 2 . . . . * * * . x * * . . * . * * * . . * $args = [ 1, 1, 0, 2, 2, 0, 0, 1 ] $height = 1, $v = 1 #### sub rearrange { my($dim, $height, $v, $args) = @_; my @bitmap = (0 .. $dim - 1); my($ones, $zeros) = (0, $dim - 1); # find holes in the ones looking from the bottom and plugs # in the zeros looking from the top, then swap them while ($ones < $zeros) { ++$ones , next if ($v & (1 << $ones )) != 0; --$zeros, next if ($v & (1 << $zeros)) == 0; @bitmap[$ones, $zeros] = @bitmap[$zeros, $ones]; ++$ones; --$zeros; } ++$ones if $ones == $zeros && ($v & (1 << $ones)) != 0; # $ones is now a count of the number of 1-bits # may need an extra swap to get the 'x' at the right height if ($bitmap[$height] != $ones) { my($lowest) = grep $bitmap[$_] == $ones, 0 .. $dim - 1; @bitmap[$height, $lowest] = @bitmap[$lowest, $height]; } # we now know what row should go where, so build and return the mapped result my @invmap = sort { $bitmap[$a] <=> $bitmap[$b] } 0 .. $dim - 1; my @vmap = (0); for (0 .. $dim - 1) { my $mapped = 1 << $invmap[$_]; push @vmap, map $_ + $mapped, @vmap; } ($bitmap[$height], [ @$args[ @vmap ] ]); }