. . . 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 ] ]);
}